提交修改

This commit is contained in:
Bob.Song
2026-03-19 16:14:33 +08:00
parent c2ec7226c0
commit 34070d0769
90 changed files with 3016 additions and 1765 deletions

View File

@@ -19,6 +19,8 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Game\Condition\" />
<Folder Include="Game\FishFarm\" />
<Folder Include="Game\Map\Weather\" />
<Folder Include="Generate\ConfigTable\" />
<Folder Include="Generate\NetworkProtocol\" />

View File

@@ -0,0 +1,42 @@
namespace NB.Game;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
public sealed class ItemUseAttribute : Attribute
{
public ItemUseEffect Type { get; }
public ItemUseAttribute(ItemUseEffect type)
{
Type = type;
}
}
public enum ItemUseEffect
{
None = 0,
Equip = 1, // 装备到身上
UnEquip = 2, // 从身上卸下
AddAttr = 3, // 增加属性
CutAttr = 4, // 减少属性
}
public interface IItemUse
{
/// <summary>
/// 正常的情况下应该是使用Unit,因为这个代表的是某一个单位。
/// 由于课程中没有这个Unit所以暂时用Account来代替。
/// </summary>
/// <param name="player"></param>
/// <param name="config"></param>
/// <param name="count"></param>
/// <returns></returns>
uint CanUse(Player player, cfg.Item config, ref int count);
/// <summary>
/// 使用物品的逻辑。
/// </summary>
/// <param name="player"></param>
/// <param name="config"></param>
/// <param name="count"></param>
void Use(Player player, cfg.Item config, ref int count);
}

View File

@@ -9,7 +9,7 @@ public enum ItemBasicType
Currency = 1,
Item = 2,
Rod = 3,
Reel =4,
Reel = 4,
Bobber = 5,
Line = 6,
Bait = 7,
@@ -60,4 +60,4 @@ public class Item : Entity
/// 正则使用中
/// </summary>
[BsonIgnore] public bool InUse;
}
}

View File

@@ -0,0 +1,196 @@
using Fantasy;
using Fantasy.Assembly;
using Fantasy.Async;
using Fantasy.DataStructure.Collection;
using Fantasy.Entitas;
namespace NB.Game;
public class ItemUseComponent : Entity, IAssemblyLifecycle
{
private readonly Dictionary<int, IItemUse> _handlers = new Dictionary<int, IItemUse>();
private readonly OneToManyList<long, int> _assemblyHandlers = new OneToManyList<long, int>();
public override void Dispose()
{
base.Dispose();
_handlers.Clear();
_assemblyHandlers.Clear();
}
public async FTask Initialize()
{
// 注册到生命周期中
await AssemblyLifecycle.Add(this);
}
#region Assembly
public async FTask OnLoad(AssemblyManifest assemblyManifest)
{
var tcs = FTask.Create(false);
Scene.ThreadSynchronizationContext.Post(() =>
{
InnerLoad(assemblyManifest);
tcs.SetResult();
});
await tcs;
}
public async FTask OnUnload(AssemblyManifest assemblyManifest)
{
var tcs = FTask.Create(false);
Scene.ThreadSynchronizationContext.Post(() =>
{
InnerUnLoad(assemblyManifest);
tcs.SetResult();
});
await tcs;
}
private void InnerLoad(AssemblyManifest assemblyManifest)
{
var assembly = assemblyManifest.Assembly;
var assemblyIdentity = assemblyManifest.AssemblyManifestId;
foreach (var type in assembly.GetTypes())
{
if (!typeof(IItemUse).IsAssignableFrom(type))
{
continue;
}
if (type.IsInterface || type.IsAbstract)
{
continue;
}
var customAttributes = type.GetCustomAttributes(typeof(ItemUseAttribute), false);
if (customAttributes.Length == 0)
{
Log.Warning(
$"type {type.FullName} Implemented the interface of IItemUse, requiring the implementation of ItemUseAttribute");
continue;
}
var instance = (IItemUse)Activator.CreateInstance(type)!;
foreach (ItemUseAttribute customAttribute in customAttributes)
{
var customAttributeType = (int)customAttribute.Type;
_handlers.Add(customAttributeType, instance);
_assemblyHandlers.Add(assemblyIdentity, customAttributeType);
}
}
}
private void InnerUnLoad(AssemblyManifest assemblyManifest)
{
var assemblyIdentity = assemblyManifest.AssemblyManifestId;
if (!_assemblyHandlers.TryGetValue(assemblyIdentity, out var assemblyHandlers))
{
return;
}
foreach (var assemblyHandler in assemblyHandlers)
{
_handlers.Remove(assemblyHandler);
}
_assemblyHandlers.Remove(assemblyIdentity);
}
#endregion
public uint CanUse(Player account, cfg.Item config, ref int count)
{
var itemUseEffect = (ItemUseEffect)config.Effect;
if (itemUseEffect == ItemUseEffect.None)
{
Log.Error($"config.Effect is zero!");
return 1;
}
return CanUse(account, config, itemUseEffect, ref count);
}
public void Use(Player account, cfg.Item config, ref int count)
{
var itemUseEffect = (ItemUseEffect)config.Effect;
if (itemUseEffect == ItemUseEffect.None)
{
Log.Error($"config.Effect is zero!");
return;
}
if (!_handlers.TryGetValue((int)itemUseEffect, out var handler))
{
return;
}
handler.Use(account, config, ref count);
}
public uint UseHandler(Player account, cfg.Item config, ref int count)
{
var itemUseEffect = (ItemUseEffect)config.Effect;
if (itemUseEffect == ItemUseEffect.None)
{
Log.Error($"config.Effect is zero!");
return 1;
}
if (!_handlers.TryGetValue((int)itemUseEffect, out var handler))
{
return 0;
}
var canUse = handler.CanUse(account, config, ref count);
if (canUse != 0)
{
return canUse;
}
handler.Use(account, config, ref count);
return 0;
}
public uint CanUse(Player account, cfg.Item config, ItemUseEffect itemUseEffect, ref int count)
{
if (!_handlers.TryGetValue((int)itemUseEffect, out var handler))
{
return 0;
}
return handler.CanUse(account, config, ref count);
}
public void Use(Player account, cfg.Item config, ItemUseEffect itemUseEffect, ref int count)
{
if (!_handlers.TryGetValue((int)itemUseEffect, out var handler))
{
return;
}
handler.Use(account, config, ref count);
}
public uint UseHandler(Player account, cfg.Item config, ItemUseEffect itemUseEffect, ref int count)
{
if (!_handlers.TryGetValue((int)itemUseEffect, out var handler))
{
return 0;
}
var canUse = handler.CanUse(account, config, ref count);
if (canUse != 0)
{
return canUse;
}
handler.Use(account, config, ref count);
return 0;
}
}

View File

@@ -0,0 +1,36 @@
using Fantasy;
using Fantasy.DataStructure.Collection;
using Fantasy.Entitas;
namespace NB;
/// <summary>
/// 邮件物流中转中心,用来存放所有离线的邮件。
/// 玩家可以在上线的第一时间去这里领取属于自己的邮件。
/// </summary>
public class MailBoxManageComponent : Entity
{
// 定时清楚过期邮件的时间
public const int MailCheckTIme = 10000;
// 存放所有邮箱都会在这里,包括发送给个人的和所有人的邮件。
public readonly Dictionary<long, MailBox> MailBoxes = new Dictionary<long, MailBox>();
// 个人领取邮件列表
public readonly OneToManyList<long, MailBox> MailsByAccount = new OneToManyList<long, MailBox>();
// 按照邮件箱类型存储
public readonly OneToManyList<int, MailBox> MailsByMailBoxType = new OneToManyList<int, MailBox>();
// 按照时间排序的邮件箱
public readonly SortedOneToManyList<long, long> Timers = new SortedOneToManyList<long, long>();
// 临时的存放过期时间的队列
public readonly Queue<long> TimeOutQueue = new Queue<long>();
// 时间任务的Id
public long TimerId;
// 最小的时间
public long MinTime;
}

View File

@@ -0,0 +1,27 @@
using System.Collections.Generic;
using Fantasy.DataStructure.Collection;
using Fantasy.Entitas;
using Fantasy.Helper;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Options;
namespace NB;
/// <summary>
/// 这个代表一个用户身上所有邮件的组件
/// </summary>
public sealed class MailComponent : Entity
{
// 最大的邮件数量
public const int MaxMailCount = 50;
// 邮件的过期时间,这个是过期7天时间。
public const int MailExpireTime = 1000 * 60 * 60 * 24 * 7;
// 玩家的邮件
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<long, Mail> Mails = new Dictionary<long, Mail>();
// 按照时间进行排序
[BsonIgnore] public readonly SortedOneToManyList<long, long> Timer = new SortedOneToManyList<long, long>();
}

View File

@@ -0,0 +1,26 @@
using System.Collections.Generic;
using Fantasy.Entitas;
using MongoDB.Bson.Serialization.Attributes;
using NB.Game;
namespace NB;
/// <summary>
/// 代表游戏中的一封邮件实体
/// </summary>
public sealed class Mail : Entity
{
// 这个代表里游戏中的一封邮件
// 标题、内容、金钱、物品
public long OwnerId; // 邮件拥有者的Id(AccountId、UnitId、RoleId)
public string Title; // 邮件的标题
public string Content; // 邮件的内容
public long CreateTime; // 邮件的创建时间
public long ExpireTime; // 邮件的过期时间(决定这个实体的生命周期)
public int Money; // 邮件的中钱
public MailState MailState; // 邮件的状态
public MailType MailType; // 邮件的类型
public List<Item> Items = new List<Item>(); // 邮件中的物品
// [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
// public Dictionary<long,Item> Items = new Dictionary<long,Item>();
}

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
using Fantasy.Entitas;
using NB;
namespace Fantasy;
/// <summary>
/// 邮件箱
/// </summary>
public sealed class MailBox : Entity
{
// 快递
// 快递包装、用盒子。然后这个盒子上有一个标签、收件人、发件人、快递的公司。
// 这个盒子了。可以装任何不同种类的东西。
// 一对一、我发一个快递,给张三和李四。
// 但是邮件可能会有这个的功能,比如给某一个范围的人发送同一份邮件,比如补偿、或者奖励。
public Mail Mail; // 邮件
public long CreateTime; // 箱子的创建时间
public long ExpireTime; // 箱子的过期时间
public MailBoxType MailBoxType; // 箱子的类型
public HashSet<long> AccountId = new HashSet<long>(); // 收件人
public HashSet<long> Received = new HashSet<long>(); // 领取过的人
public long SendAccountId; // 发件人/发送人
}

View File

@@ -0,0 +1,58 @@
// using System.Collections.Generic;
// using Fantasy.Entitas;
// using MongoDB.Bson.Serialization.Attributes;
//
// namespace NB.Chat;
//
// public class MailConversation : Entity
// {
// /// <summary>
// /// 第一id
// /// </summary>
// [BsonElement("id1")] public long FirstId;
//
// /// <summary>
// /// 第二id
// /// </summary>
// [BsonElement("id2")] public long SecondId;
//
// /// <summary>
// /// 会话
// /// </summary>
// [BsonElement("list")] public List<Mail> Mails = new List<Mail>();
//
// /// <summary>
// /// 第一个阅读时间
// /// </summary>
// [BsonElement("ft")] public long FirstReadTime;
//
// /// <summary>
// /// 第二阅读时间
// /// </summary>
// [BsonElement("st")] public long SecondReadTime;
//
// /// <summary>
// /// 最后更新时间
// /// </summary>
// [BsonElement("ut")] public long UpdateTime;
//
// /// <summary>
// /// 删除人标志
// /// </summary>
// [BsonElement("rid")] public HashSet<long> RemoveId = new HashSet<long>();
//
// /// <summary>
// /// 会话keyid-id按大小排序
// /// </summary>
// [BsonIgnore] public string Key = string.Empty;
//
// /// <summary>
// /// 最后保存时间
// /// </summary>
// [BsonIgnore] public long NeedSaveTime = 0;
//
// /// <summary>
// /// 需要保存
// /// </summary>
// [BsonIgnore] public bool NeedSave;
// }

View File

@@ -0,0 +1,35 @@
namespace NB;
public enum MailType
{
None = 0,
System = 1, // 系统邮件
Rewards = 2, // 奖励邮件(擂台、有奖问答)
User = 3, // 个人邮件(玩家给玩家之间发送)
}
public enum MailState
{
None = 0,
Unread = 1, // 未读
HaveRead = 2, // 已读
NotClaimed = 3, // 未领取
Received = 4, // 已领取
}
public enum MailBoxType
{
None = 0,
Specify = 1, // 指定目标
Online = 2, // 给在线所有人发送邮件
All = 3, // 所有人
AllToDate = 4, // 根据玩家注册的时间发送邮件
}
public enum MailRemoveActionType
{
None = 0,
Remove = 1, // 手动移除
ExpireTimeRemove = 2, // 过期时间移除
Overtop = 3, // 超过邮件上限移除
}

View File

@@ -62,6 +62,11 @@ public sealed class Player : Entity
/// </summary>
[BsonElement("vExTime")] public long VipExpirationTime;
/// <summary>
/// 创建时间
/// </summary>
public long CreateTime;
[BsonIgnore] public long SessionRunTimeId;

View File

@@ -1,35 +0,0 @@
using System.Collections.Generic;
using Fantasy.DataStructure.Collection;
using Fantasy.Entitas;
using Fantasy.Helper;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Options;
namespace NB.Chat;
/// <summary>
/// 玩家邮件组件
/// </summary>
public class MailComponent : Entity
{
/// <summary>
/// 最大邮件数据
/// </summary>
public const int MaxMailCount = 50;
/// <summary>
/// 邮件最大保留时间
/// </summary>
public const long MaxExpireTime = TimeHelper.OneDay * 365;
/// <summary>
/// 邮件列表
/// </summary>
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<long, Mail> Mails = new Dictionary<long, Mail>();
/// <summary>
/// 按照时间进行排序
/// </summary>
[BsonIgnore] public readonly SortedOneToManyListPool<long, long> Timer = new SortedOneToManyListPool<long, long>();
}

View File

@@ -1,20 +0,0 @@
using System.Collections.Generic;
using Fantasy.Entitas;
namespace NB.Chat;
/// <summary>
/// 邮件管理组件
/// </summary>
public class MailManageComponent : Entity
{
/// <summary>
/// 会话列表
/// </summary>
public Dictionary<string, MailConversation> Conversations = new Dictionary<string, MailConversation>();
/// <summary>
/// 缓存了的列表
/// </summary>
public HashSet<long> CacheRoleIds = new HashSet<long>();
}

View File

@@ -1,49 +0,0 @@
using System.Collections.Generic;
using Fantasy.Entitas;
using MongoDB.Bson.Serialization.Attributes;
using NB.Game;
namespace NB.Chat;
public sealed class Mail : Entity
{
/// <summary>
/// 邮件发送者
/// </summary>
[BsonElement("send")] public long Sender;
/// <summary>
/// 邮件拥有者
/// </summary>
[BsonElement("owner")] public long OwnerId;
/// <summary>
/// 邮件状态
/// </summary>
[BsonElement("state")] public MailState State = MailState.None;
/// <summary>
/// 邮件状态
/// </summary>
[BsonElement("type")] public MailType MailType = MailType.None;
/// <summary>
/// 邮件内容
/// </summary>
[BsonElement("con")] public string Content;
/// <summary>
/// 创建时间
/// </summary>
[BsonElement("ct")] public long CreateTime;
/// <summary>
/// 过期时间
/// </summary>
[BsonElement("et")] public long ExpireTime;
/// <summary>
/// 邮件的附件内容
/// </summary>
[BsonElement("item")] public List<AwardItem> Items = new List<AwardItem>();
}

View File

@@ -1,45 +0,0 @@
using System.Collections.Generic;
using Fantasy.Entitas;
namespace NB.Chat;
/// <summary>
/// 邮件箱,系统群发用
/// </summary>
public class MailBox : Entity
{
/// <summary>
/// 邮件
/// </summary>
public Mail Mail;
/// <summary>
/// 创建时间
/// </summary>
public long CreateTime;
/// <summary>
/// 失效时间
/// </summary>
public long ExpireTime;
/// <summary>
/// 邮箱类型
/// </summary>
public MailBoxType BoxType;
/// <summary>
/// 发送人
/// </summary>
public long SendAccountId = 0;
/// <summary>
/// 收件人
/// </summary>
public HashSet<long> AccountId = new HashSet<long>();
/// <summary>
/// 领取过的人
/// </summary>
public HashSet<long> Received = new HashSet<long>();
}

View File

@@ -1,58 +0,0 @@
using System.Collections.Generic;
using Fantasy.Entitas;
using MongoDB.Bson.Serialization.Attributes;
namespace NB.Chat;
public class MailConversation : Entity
{
/// <summary>
/// 第一id
/// </summary>
[BsonElement("id1")] public long FirstId;
/// <summary>
/// 第二id
/// </summary>
[BsonElement("id2")] public long SecondId;
/// <summary>
/// 会话
/// </summary>
[BsonElement("list")] public List<Mail> Mails = new List<Mail>();
/// <summary>
/// 第一个阅读时间
/// </summary>
[BsonElement("ft")] public long FirstReadTime;
/// <summary>
/// 第二阅读时间
/// </summary>
[BsonElement("st")] public long SecondReadTime;
/// <summary>
/// 最后更新时间
/// </summary>
[BsonElement("ut")] public long UpdateTime;
/// <summary>
/// 删除人标志
/// </summary>
[BsonElement("rid")] public HashSet<long> RemoveId = new HashSet<long>();
/// <summary>
/// 会话keyid-id按大小排序
/// </summary>
[BsonIgnore] public string Key = string.Empty;
/// <summary>
/// 最后保存时间
/// </summary>
[BsonIgnore] public long NeedSaveTime = 0;
/// <summary>
/// 需要保存
/// </summary>
[BsonIgnore] public bool NeedSave;
}

View File

@@ -1,54 +0,0 @@
namespace NB.Chat;
public enum MailType
{
None = 0,
System = 1, //系统邮件
Rewards = 2, //奖励邮件
User = 3, //个人邮件
}
public enum MailState
{
None = 0,
/// <summary>
/// 未读
/// </summary>
Unread = 1,
/// <summary>
/// 已读
/// </summary>
HaveRead = 2,
/// <summary>
/// 未领取
/// </summary>
NotClaimed = 3,
/// <summary>
/// 已领取
/// </summary>
Received = 4,
/// <summary>
/// 已删除
/// </summary>
Deleted = 5,
}
public enum MailBoxType
{
None = 0,
/// <summary>
/// 指定目标
/// </summary>
Specify = 1,
/// <summary>
/// 全部人
/// </summary>
All = 2
}

View File

@@ -1,33 +0,0 @@
// using Fantasy;
// using Fantasy.Entitas;
//
// namespace NB.Chat;
//
// public sealed class SocialUnit : Entity
// {
// public long GateRouteId;
//
// public RoleSimpleInfo Role;
//
// /// <summary>
// /// 当前所在地图
// /// </summary>
// public long MapId;
//
//
// public readonly Dictionary<long, ChatChannelComponent> Channels = new();
// public readonly Dictionary<int, long> SendTime = new Dictionary<int, long>();
//
//
// public override void Dispose()
// {
// if (IsDisposed)
// {
// return;
// }
//
// GateRouteId = 0;
// Role = null;
// base.Dispose();
// }
// }

View File

@@ -1,17 +0,0 @@
// using System.Collections.Generic;
// using Fantasy;
// using Fantasy.DataStructure.Collection;
// using Fantasy.Entitas;
//
// namespace NB.Chat;
//
// public class SocialUnitManageComponent : Entity
// {
// public readonly Dictionary<long, SocialUnit> Units = new();
//
// // public List<MailBox>
// // /// <summary>
// // /// 不在线消息缓存
// // /// </summary>
// // public readonly OneToManyList<long, ChatMessageInfo> NotSendMessage = new();
// }

View File

@@ -25,6 +25,7 @@ public sealed partial class Fish : Luban.BeanBase
MinWeight = (int)_obj.GetValue("min_weight");
MaxWeight = (int)_obj.GetValue("max_weight");
Accept = (int)_obj.GetValue("accept");
Water = (int)_obj.GetValue("water");
}
public static Fish DeserializeFish(JToken _buf)
@@ -52,6 +53,10 @@ public sealed partial class Fish : Luban.BeanBase
/// 接受的鱼饵配置组
/// </summary>
public readonly int Accept;
/// <summary>
/// 需要的水
/// </summary>
public readonly int Water;
public const int __ID__ = 2189944;
@@ -69,6 +74,7 @@ public sealed partial class Fish : Luban.BeanBase
+ "minWeight:" + MinWeight + ","
+ "maxWeight:" + MaxWeight + ","
+ "accept:" + Accept + ","
+ "water:" + Water + ","
+ "}";
}
}

View File

@@ -28,6 +28,7 @@ public sealed partial class Item : Luban.BeanBase
Length = (int)_obj.GetValue("length");
Max = (int)_obj.GetValue("max");
AutoUse = (int)_obj.GetValue("auto_use");
Effect = (int)_obj.GetValue("effect");
{ var __json0 = _obj.GetValue("result1"); Result1 = new System.Collections.Generic.List<int>((__json0 as JArray).Count); foreach(JToken __e0 in __json0) { int __v0; __v0 = (int)__e0; Result1.Add(__v0); } }
{ var __json0 = _obj.GetValue("result2"); Result2 = new System.Collections.Generic.List<string>((__json0 as JArray).Count); foreach(JToken __e0 in __json0) { string __v0; __v0 = (string)__e0; Result2.Add(__v0); } }
}
@@ -70,6 +71,10 @@ public sealed partial class Item : Luban.BeanBase
/// </summary>
public readonly int AutoUse;
/// <summary>
/// 使用效果
/// </summary>
public readonly int Effect;
/// <summary>
/// 使用参数1
/// </summary>
public readonly System.Collections.Generic.List<int> Result1;
@@ -97,6 +102,7 @@ public sealed partial class Item : Luban.BeanBase
+ "length:" + Length + ","
+ "max:" + Max + ","
+ "autoUse:" + AutoUse + ","
+ "effect:" + Effect + ","
+ "result1:" + Luban.StringUtil.CollectionToString(Result1) + ","
+ "result2:" + Luban.StringUtil.CollectionToString(Result2) + ","
+ "}";

View File

@@ -0,0 +1,64 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using Luban;
using Newtonsoft.Json.Linq;
namespace cfg
{
public sealed partial class Leader : Luban.BeanBase
{
public Leader(JToken _buf)
{
JObject _obj = _buf as JObject;
Id = (int)_obj.GetValue("id");
Strength = (int)_obj.GetValue("strength");
Size = (int)_obj.GetValue("size");
}
public static Leader DeserializeLeader(JToken _buf)
{
return new Leader(_buf);
}
/// <summary>
/// Id
/// </summary>
public readonly int Id;
/// <summary>
/// 强度
/// </summary>
public readonly int Strength;
/// <summary>
/// 尺寸
/// </summary>
public readonly int Size;
public const int __ID__ = -2022887127;
public override int GetTypeId() => __ID__;
public void ResolveRef(Tables tables)
{
}
public override string ToString()
{
return "{ "
+ "id:" + Id + ","
+ "strength:" + Strength + ","
+ "size:" + Size + ","
+ "}";
}
}
}

View File

@@ -50,6 +50,10 @@ public partial class Tables
/// </summary>
public TbItem TbItem {get; }
/// <summary>
/// 引线
/// </summary>
public TbLeader TbLeader {get; }
/// <summary>
/// 鱼线
/// </summary>
public TbLine TbLine {get; }
@@ -82,6 +86,7 @@ public partial class Tables
TbHook = new TbHook(loader("tbhook"));
TbInitItemConfig = new TbInitItemConfig(loader("tbinititemconfig"));
TbItem = new TbItem(loader("tbitem"));
TbLeader = new TbLeader(loader("tbleader"));
TbLine = new TbLine(loader("tbline"));
TbLure = new TbLure(loader("tblure"));
TbReel = new TbReel(loader("tbreel"));
@@ -101,6 +106,7 @@ public partial class Tables
TbHook.ResolveRef(this);
TbInitItemConfig.ResolveRef(this);
TbItem.ResolveRef(this);
TbLeader.ResolveRef(this);
TbLine.ResolveRef(this);
TbLure.ResolveRef(this);
TbReel.ResolveRef(this);

View File

@@ -0,0 +1,58 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using Newtonsoft.Json.Linq;
using Luban;
namespace cfg
{
/// <summary>
/// 引线
/// </summary>
public partial class TbLeader
{
private readonly System.Collections.Generic.Dictionary<int, Leader> _dataMap;
private readonly System.Collections.Generic.List<Leader> _dataList;
public TbLeader(JArray _buf)
{
_dataMap = new System.Collections.Generic.Dictionary<int, Leader>(_buf.Count);
_dataList = new System.Collections.Generic.List<Leader>(_buf.Count);
foreach(JObject _ele in _buf)
{
Leader _v;
_v = global::cfg.Leader.DeserializeLeader(_ele);
_dataList.Add(_v);
_dataMap.Add(_v.Id, _v);
}
}
public System.Collections.Generic.Dictionary<int, Leader> DataMap => _dataMap;
public System.Collections.Generic.List<Leader> DataList => _dataList;
public Leader GetOrDefault(int key) => _dataMap.TryGetValue(key, out var v) ? v : default;
public Leader Get(int key) => _dataMap[key];
public Leader this[int key] => _dataMap[key];
public void ResolveRef(Tables tables)
{
foreach(var _v in _dataList)
{
_v.ResolveRef(tables);
}
}
}
}

View File

@@ -678,4 +678,89 @@ namespace Fantasy
[ProtoMember(1)]
public ChatInfoTree ChatInfoTree { get; set; }
}
/// <summary>
/// 其他服务器发送邮件
/// </summary>
////////// ******** 邮件 *******/////////////
public partial class Other2Mail_SendMailRequest : AMessage, IAddressRequest
{
public static Other2Mail_SendMailRequest Create(bool autoReturn = true)
{
var other2Mail_SendMailRequest = MessageObjectPool<Other2Mail_SendMailRequest>.Rent();
other2Mail_SendMailRequest.AutoReturn = autoReturn;
if (!autoReturn)
{
other2Mail_SendMailRequest.SetIsPool(false);
}
return other2Mail_SendMailRequest;
}
public void Return()
{
if (!AutoReturn)
{
SetIsPool(true);
AutoReturn = true;
}
else if (!IsPool())
{
return;
}
Dispose();
}
public void Dispose()
{
if (!IsPool()) return;
MailBox = default;
MessageObjectPool<Other2Mail_SendMailRequest>.Return(this);
}
public uint OpCode() { return InnerOpcode.Other2Mail_SendMailRequest; }
[BsonIgnore]
public Mail2Other_SendMailResponse ResponseType { get; set; }
public MailBox MailBox { get; set; }
}
[Serializable]
[ProtoContract]
public partial class Mail2Other_SendMailResponse : AMessage, IAddressResponse
{
public static Mail2Other_SendMailResponse Create(bool autoReturn = true)
{
var mail2Other_SendMailResponse = MessageObjectPool<Mail2Other_SendMailResponse>.Rent();
mail2Other_SendMailResponse.AutoReturn = autoReturn;
if (!autoReturn)
{
mail2Other_SendMailResponse.SetIsPool(false);
}
return mail2Other_SendMailResponse;
}
public void Return()
{
if (!AutoReturn)
{
SetIsPool(true);
AutoReturn = true;
}
else if (!IsPool())
{
return;
}
Dispose();
}
public void Dispose()
{
if (!IsPool()) return;
ErrorCode = 0;
MessageObjectPool<Mail2Other_SendMailResponse>.Return(this);
}
public uint OpCode() { return InnerOpcode.Mail2Other_SendMailResponse; }
[ProtoMember(1)]
public uint ErrorCode { get; set; }
}
}

View File

@@ -20,5 +20,7 @@ namespace Fantasy
public const uint Map2G_ExiRoomResponse = 1207969557;
public const uint Chat2G_ChatMessage = 939534099;
public const uint Other2Chat_ChatMessage = 939534100;
public const uint Other2Mail_SendMailRequest = 1082140438;
public const uint Mail2Other_SendMailResponse = 1207969558;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -27,63 +27,69 @@ namespace Fantasy
public const uint Game2C_RewardNotify = 2147493651;
public const uint C2Game_GMRequest = 2281711385;
public const uint Game2C_GMResponse = 2415929113;
public const uint C2Game_CreateRoomRequest = 2281711386;
public const uint Game2C_CreateRoomResponse = 2415929114;
public const uint C2Mail_TestRequest = 2281711386;
public const uint Mail2C_TestResponse = 2415929114;
public const uint Mail2C_HaveMail = 2147493652;
public const uint Mail2C_MailState = 2147493653;
public const uint C2Mail_GetHaveMailRequest = 2281711387;
public const uint Mail2C_GetHaveMailResposne = 2415929115;
public const uint C2Mail_OpenMailRequest = 2281711388;
public const uint Mail2C_OpenMailResposne = 2415929116;
public const uint C2Mail_ReceiveMailRequest = 2281711389;
public const uint Mail2C_ReceiveMailResponse = 2415929117;
public const uint C2Mail_RemoveMailRequest = 2281711390;
public const uint Mail2C_RemoveMailResponse = 2415929118;
public const uint C2Mail_SendMailRequest = 2281711391;
public const uint Mail2C_SendMailResponse = 2415929119;
public const uint C2Game_CreateRoomRequest = 2281711392;
public const uint Game2C_CreateRoomResponse = 2415929120;
public const uint C2G_ExitRoomRequest = 268445457;
public const uint G2C_ExitRoomResponse = 402663185;
public const uint C2G_EnterMapRequest = 268445458;
public const uint G2C_EnterMapResponse = 402663186;
public const uint Game2C_ChangeMap = 2147493652;
public const uint Game2C_ChangeMap = 2147493654;
public const uint C2A_LoginRequest = 268445459;
public const uint A2C_LoginResponse = 402663187;
public const uint C2G_LoginRequest = 268445460;
public const uint G2C_LoginResponse = 402663188;
public const uint G2C_RepeatLogin = 134227729;
public const uint C2Game_GetRoleInfoRequest = 2281711387;
public const uint Game2C_GetRoleInfoResponse = 2415929115;
public const uint Game2C_RoleEnterRoomNotify = 2147493653;
public const uint Game2C_RoleExitRoomNotify = 2147493654;
public const uint C2Game_TakeItemRequest = 2281711388;
public const uint Game2C_TakeItemResponse = 2415929116;
public const uint C2Game_RolePropertyChange = 2147493655;
public const uint Game2C_RoleStateNotify = 2147493656;
public const uint Game2C_RoleGearChangeNotify = 2147493657;
public const uint Game2C_RolePropertyChangeNotify = 2147493658;
public const uint C2Game_Move = 2147493659;
public const uint C2Game_Look = 2147493660;
public const uint Game2C_MoveNotify = 2147493661;
public const uint Game2C_LookeNotify = 2147493662;
public const uint C2Game_GetConversationsRequest = 2281711389;
public const uint Game2C_GetConversationsResponse = 2415929117;
public const uint C2Game_SendMailRequest = 2281711390;
public const uint Game2C_SendMailResponse = 2415929118;
public const uint C2Game_DeleteMailRequest = 2281711391;
public const uint Game2C_DeleteMailResponse = 2415929119;
public const uint Game2C_HaveMail = 2147493663;
public const uint Game2C_MailState = 2147493664;
public const uint C2Game_SendMessageRequest = 2281711392;
public const uint Game2C_SendMessageResponse = 2415929120;
public const uint C2Game_GetRoleInfoRequest = 2281711393;
public const uint Game2C_GetRoleInfoResponse = 2415929121;
public const uint Game2C_RoleEnterRoomNotify = 2147493655;
public const uint Game2C_RoleExitRoomNotify = 2147493656;
public const uint C2Game_TakeItemRequest = 2281711394;
public const uint Game2C_TakeItemResponse = 2415929122;
public const uint C2Game_RolePropertyChange = 2147493657;
public const uint Game2C_RoleStateNotify = 2147493658;
public const uint Game2C_RoleGearChangeNotify = 2147493659;
public const uint Game2C_RolePropertyChangeNotify = 2147493660;
public const uint C2Game_Move = 2147493661;
public const uint C2Game_Look = 2147493662;
public const uint Game2C_MoveNotify = 2147493663;
public const uint Game2C_LookeNotify = 2147493664;
public const uint C2Game_SendMessageRequest = 2281711395;
public const uint Game2C_SendMessageResponse = 2415929123;
public const uint Game2C_Message = 2147493665;
public const uint C2Game_CreateChannelRequest = 2281711393;
public const uint Game2C_CreateChannelResponse = 2415929121;
public const uint C2Game_JoinChannelRequest = 2281711394;
public const uint Game2C_JoinChannelResponse = 2415929122;
public const uint C2Game_CreateClubRequest = 2281711395;
public const uint Game2C_CreateClubResponse = 2415929123;
public const uint C2Game_GetClubInfoRequest = 2281711396;
public const uint Game2C_GetClubInfoResponse = 2415929124;
public const uint C2Game_GetMemberListRequest = 2281711397;
public const uint Game2C_GetMemberListResponse = 2415929125;
public const uint C2Game_GetClubListRequest = 2281711398;
public const uint Game2C_GetClubListResponse = 2415929126;
public const uint C2Game_JoinClubRequest = 2281711399;
public const uint Game2C_JoinClubResponse = 2415929127;
public const uint C2Game_LeaveClubRequest = 2281711400;
public const uint Game2C_LeaveClubResponse = 2415929128;
public const uint C2Game_DissolveClubRequest = 2281711401;
public const uint Game2C_DissolveClubResponse = 2415929129;
public const uint C2Game_DisposeJoinRequest = 2281711402;
public const uint Game2C_DisposeJoinResponse = 2415929130;
public const uint C2Game_CreateChannelRequest = 2281711396;
public const uint Game2C_CreateChannelResponse = 2415929124;
public const uint C2Game_JoinChannelRequest = 2281711397;
public const uint Game2C_JoinChannelResponse = 2415929125;
public const uint C2Game_CreateClubRequest = 2281711398;
public const uint Game2C_CreateClubResponse = 2415929126;
public const uint C2Game_GetClubInfoRequest = 2281711399;
public const uint Game2C_GetClubInfoResponse = 2415929127;
public const uint C2Game_GetMemberListRequest = 2281711400;
public const uint Game2C_GetMemberListResponse = 2415929128;
public const uint C2Game_GetClubListRequest = 2281711401;
public const uint Game2C_GetClubListResponse = 2415929129;
public const uint C2Game_JoinClubRequest = 2281711402;
public const uint Game2C_JoinClubResponse = 2415929130;
public const uint C2Game_LeaveClubRequest = 2281711403;
public const uint Game2C_LeaveClubResponse = 2415929131;
public const uint C2Game_DissolveClubRequest = 2281711404;
public const uint Game2C_DissolveClubResponse = 2415929132;
public const uint C2Game_DisposeJoinRequest = 2281711405;
public const uint Game2C_DisposeJoinResponse = 2415929133;
public const uint Game2C_ClubChange = 2147493666;
}
}

View File

@@ -0,0 +1,74 @@
namespace NB.Game;
public static class ItemUseHelper
{
// public static uint UseBagItem(Account account, long itemId, int count)
// {
// return UseItem(account, ContainerType.Bag, itemId, count);
// }
//
// public static uint CanUseBagItem(Account account, long itemId, int count, out Container container, out ItemConfig itemConfig, out ItemUseComponent itemUseComponent)
// {
// return CanUseItem(account, ContainerType.Bag, itemId, count, out container, out itemConfig, out itemUseComponent);
// }
//
// public static uint UseItem(Account account, ContainerType containerType, long itemId, int count)
// {
// var errorCode = CanUseItem(account, containerType, itemId, count, out var container, out var itemConfig, out var itemUseComponent);
//
// if (errorCode != 0)
// {
// return errorCode;
// }
//
// errorCode = container.RemoveItem(itemId, count, ItemReason.ItemUse, true);
//
// if (errorCode != 0)
// {
// return errorCode;
// }
//
// itemUseComponent.Use(account, itemConfig, ref count);
// return 0;
// }
//
// public static uint CanUseItem(Player account, long itemId, int count, out cfg.Item itemConfig,
// out ItemUseComponent itemUseComponent)
// {
// itemConfig = null;
// itemUseComponent = null;
// var errorCode = ContainerHelper.TryGetContainer(account, containerType, out container);
//
// if (errorCode != 0)
// {
// return errorCode;
// }
//
// if (!container.GetItemById(itemId, out var item))
// {
// // 这里是找不到该物品的错误码。
// return 1;
// }
//
// if (item.Count < count)
// {
// // 这里是物品数量不足的错误码。
// return 2;
// }
//
// itemConfig = item.Config;
//
// if (itemConfig.Params.Length <= 0)
// {
// // 这里是物品没有配置参数的错误码。
// return 3;
// }
//
// // 这里还可以增加一些其他的判定,比如物品是否过期,物品是否被锁定等。
// // 甚至还有物品使用的CD。
// // 使用物品效果来判定
// itemUseComponent = account.Scene.GetComponent<ItemUseComponent>();
// return itemUseComponent.CanUse(account, item.Config, ref count);
// }
}

View File

@@ -0,0 +1,51 @@
using Fantasy;
namespace NB.Game;
[ItemUse(ItemUseEffect.AddAttr)]
public class ItemUse_Drug_AddAttr : IItemUse
{
// public uint CanUse(Account account, ItemConfig config, ref int count)
// {
// if (config.Params.Length < 2)
// {
// Log.Error($"configId:{config.Id} config.Params.Length({config.Params.Length}) < 2");
// return 1;
// }
//
// Log.Debug($"CanUse 使用了药品增加属性 configId:{config.Id} count:{count}");
// return 0;
// }
//
// public void Use(Account account, ItemConfig config, ref int count)
// {
// for (int i = 0; i < config.Params.Length; i += 2)
// {
// var attrKey = config.Params[i];
// var attrValue = config.Params[i + 1];
// Log.Debug($"Use 使用了药品增加属性 configId:{config.Id} attrKey:{attrKey} attrValue:{attrValue}");
// }
// }
public uint CanUse(Player player, cfg.Item config, ref int count)
{
// if (config.Params.Length < 2)
// {
// Log.Error($"configId:{config.Id} config.Params.Length({config.Params.Length}) < 2");
// return 1;
// }
//
Log.Debug($"CanUse 使用了药品增加属性 configId:{config.Id} count:{count}");
return 0;
}
public void Use(Player player, cfg.Item config, ref int count)
{
// for (int i = 0; i < config.Params.Length; i += 2)
// {
// var attrKey = config.Params[i];
// var attrValue = config.Params[i + 1];
// Log.Debug($"Use 使用了药品增加属性 configId:{config.Id} attrKey:{attrKey} attrValue:{attrValue}");
// }
Log.Debug($"Use 使用了药品增加属性 configId:{config.Id} count:{count}");
}
}

View File

@@ -0,0 +1,18 @@
using Fantasy;
namespace NB.Game;
[ItemUse(ItemUseEffect.Equip)]
public class ItemUse_Equip_Equip : IItemUse
{
public uint CanUse(Player player, cfg.Item config, ref int count)
{
Log.Debug($"CanUse 使用了装备装备到身上 configId:{config.Id} count:{count}");
return 0;
}
public void Use(Player player, cfg.Item config, ref int count)
{
Log.Debug($"Use 使用了装备装备到身上 configId:{config.Id} count:{count}");
}
}

View File

@@ -0,0 +1,14 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network.Interface;
using NBF;
namespace NB;
public class Other2Mail_SendRequestHandler : AddressRPC<Scene, Other2Mail_SendMailRequest, Mail2Other_SendMailResponse>
{
protected override async FTask Run(Scene scene, Other2Mail_SendMailRequest request, Mail2Other_SendMailResponse response, Action reply)
{
await MailHelper.Send(scene, request.MailBox);
}
}

View File

@@ -0,0 +1,29 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network.Interface;
using NB.Game;
using NBF;
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
namespace NB;
public sealed class C2Mail_GetHaveMailRequestHandler : AddressRPC<Player, C2Mail_GetHaveMailRequest, Mail2C_GetHaveMailResposne>
{
protected override async FTask Run(Player mailUnit, C2Mail_GetHaveMailRequest request, Mail2C_GetHaveMailResposne response, Action reply)
{
var mailComponent = mailUnit.GetComponent<MailComponent>();
// 这个mailComponent是不是可能会为空?答案是可能的。
// 那如果是空的怎么办呢,这样情况只能是别人恶意发包了。
if (mailComponent == null)
{
return;
}
// 检查是否有超时的邮件。如果有那就清楚掉
await mailComponent.CheckTimeOut();
// 领取当前的邮件
mailComponent.GetMailSimplifyInfos(response.Mails);
}
}

View File

@@ -0,0 +1,35 @@
using Fantasy.Async;
using Fantasy.Network.Interface;
using NB;
using NB.Game;
using NBF;
namespace Fantasy;
public class C2Mail_OpenMailRequestHandler : AddressRPC<Player, C2Mail_OpenMailRequest, Mail2C_OpenMailResposne>
{
protected override async FTask Run(Player mailUnit, C2Mail_OpenMailRequest request, Mail2C_OpenMailResposne response, Action reply)
{
if (request.MailId <= 0)
{
response.ErrorCode = 100;
return;
}
// 根据这个MailId来拿到邮件的详细信息
var (errorCode, mail) = await mailUnit.GetComponent<MailComponent>().OpenMail(request.MailId);
if (errorCode != 0)
{
response.ErrorCode = errorCode;
return;
}
if (!request.ReturnMailInfo)
{
return;
}
response.MailInfo = mail.ToMailInfo();
}
}

View File

@@ -0,0 +1,22 @@
using Fantasy.Async;
using Fantasy.Network.Interface;
using NB;
using NB.Game;
using NBF;
namespace Fantasy;
public class C2Mail_ReceiveMailRequestHandler : AddressRPC<Player, C2Mail_ReceiveMailRequest, Mail2C_ReceiveMailResponse>
{
protected override async FTask Run(Player mailUnit, C2Mail_ReceiveMailRequest request, Mail2C_ReceiveMailResponse response, Action reply)
{
if (request.MailId <= 0)
{
response.ErrorCode = 100;
return;
}
response.ErrorCode = await mailUnit.GetComponent<MailComponent>()
.Receive(request.MailId, request.Money, request.ItemId, true);
}
}

View File

@@ -0,0 +1,24 @@
using Fantasy.Async;
using Fantasy.Network.Interface;
using NB;
using NB.Game;
using NBF;
namespace Fantasy;
public class C2Mail_RemoveMailRequestHandler : AddressRPC<Player,C2Mail_RemoveMailRequest, Mail2C_RemoveMailResponse>
{
protected override async FTask Run(Player mailUnit, C2Mail_RemoveMailRequest request, Mail2C_RemoveMailResponse response, Action reply)
{
if (request.MailId <= 0)
{
// 这里的1代表MailId不正确。
response.ErrorCode = 1;
return;
}
response.ErrorCode = await mailUnit.GetComponent<MailComponent>()
.Remove(request.MailId, MailRemoveActionType.Remove, true);
}
}

View File

@@ -0,0 +1,73 @@
using Fantasy.Async;
using Fantasy.DataStructure.Collection;
using Fantasy.Network.Interface;
using NB;
using NB.Game;
using NBF;
namespace Fantasy;
public class C2Mail_SendMailRequestHandler : AddressRPC<Player, C2Mail_SendMailRequest, Mail2C_SendMailResponse>
{
protected override async FTask Run(Player mailUnit, C2Mail_SendMailRequest request,
Mail2C_SendMailResponse response, Action reply)
{
if (request.UserId < 1)
{
// 这里的1代表的是发送的接收玩家名字不正确。
response.ErrorCode = 1;
return;
}
if (string.IsNullOrEmpty(request.Title) || string.IsNullOrEmpty(request.Content))
{
// 这里的2代表的是发送的邮件标题或者内容不正确。
response.ErrorCode = 2;
return;
}
if (request.ItemId.Count > 10)
{
// 这里的3代表的是发送的邮件附件超出了最大范围。
response.ErrorCode = 3;
return;
}
if (!mailUnit.Scene.GetComponent<PlayerManageComponent>().TryGet(request.UserId, out var receiveMailUnit))
{
// 这里的4代表的是没有该玩家。
response.ErrorCode = 4;
return;
}
if (request.Money > 0)
{
// 如果大于0就要调用某一个接口去货币所在的服务器上面去扣除玩家的钱。
// var moneyResposne = await MoneyHelper.Cost(mailUnit.Scene, request.Money);
// if (moneyResposne.ErrorCode != 0)
// {
// response.ErrorCode = moneyResposne.ErrorCode;
// return;
// }
}
using var mailItems = ListPool<Item>.Create();
if (request.ItemId.Count > 0)
{
// var itemResposne = await BagHelper.Get(mailUnit.Scene, request.ItemId);
// if (itemResposne.ErrorCode != 0)
// {
// response.ErrorCode = itemResposne.ErrorCode;
// return;
// }
// mailItems.AddRange(itemResposne.Items);
}
var accountId = ListPool<long>.Create(receiveMailUnit.Id);
var mail = MailFactory.Create(mailUnit.Scene, MailType.User, request.Title, request.Content, request.Money,
mailItems);
var mailBox = MailBoxFactory.Create(mailUnit.Scene, MailBoxType.Specify, mailUnit.Id, mail,
1000 * 60 * 60, accountId);
await MailHelper.Send(mailUnit.Scene, mailBox);
}
}

View File

@@ -0,0 +1,22 @@
using Fantasy.Async;
using Fantasy.DataStructure.Collection;
using Fantasy.Network.Interface;
using NB;
using NB.Game;
using NBF;
namespace Fantasy;
public class C2Mail_TestRequestHandler : AddressRPC<Player, C2Mail_TestRequest, Mail2C_TestResponse>
{
protected override async FTask Run(Player mailUnit, C2Mail_TestRequest request, Mail2C_TestResponse response, Action reply)
{
Log.Debug($"这是一个测试的自定义消息协议 Tag:{mailUnit.Id}");
response.Tag = "666";
// using var accountId = ListPool<long>.Create(65491190472245249);
var mail = MailFactory.Create(mailUnit.Scene, MailType.System, "测试所有人指定日期玩家邮件", "测试所有人指定日期玩家邮件内容", 9991);
var mailBox = MailBoxFactory.Create(mailUnit.Scene, MailBoxType.AllToDate, mailUnit.Id, mail,
1000 * 60 * 60);
await MailHelper.Send(mailUnit.Scene, mailBox);
}
}

View File

@@ -0,0 +1,65 @@
using Fantasy;
using Fantasy.Entitas;
using Fantasy.Helper;
using NB;
using NB.Game;
namespace NBF;
public static class MailBoxFactory
{
/// <summary>
/// 创建一个邮件箱
/// </summary>
/// <param name="scene"></param>
/// <param name="mailBoxType"></param>
/// <param name="sendAccountId"></param>
/// <param name="mail"></param>
/// <param name="expireTime"></param>
/// <param name="accountId"></param>
/// <returns></returns>
public static MailBox Create(Scene scene, MailBoxType mailBoxType, long sendAccountId, Mail mail, int expireTime,
List<long> accountId = null)
{
var mailBox = Entity.Create<MailBox>(scene, true, true);
mailBox.SendAccountId = sendAccountId;
mailBox.Mail = mail;
mailBox.MailBoxType = mailBoxType;
mailBox.CreateTime = TimeHelper.Now;
mailBox.ExpireTime = mailBox.CreateTime + expireTime;
if (accountId == null || accountId.Count <= 0)
{
return mailBox;
}
foreach (var raId in accountId)
{
mailBox.AccountId.Add(raId);
}
return mailBox;
}
/// <summary>
/// 创建一个邮件箱
/// </summary>
/// <param name="scene"></param>
/// <param name="mailType"></param>
/// <param name="mailBoxType"></param>
/// <param name="title"></param>
/// <param name="content"></param>
/// <param name="money"></param>
/// <param name="items"></param>
/// <param name="sendAccountId"></param>
/// <param name="expireTime"></param>
/// <param name="accountId"></param>
/// <returns></returns>
public static MailBox Create(Scene scene, MailType mailType, MailBoxType mailBoxType, string title, string content,
int money, List<Item> items,
long sendAccountId, int expireTime, List<long> accountId = null)
{
var mail = MailFactory.Create(scene, mailType, title, content, money, items);
return Create(scene, mailBoxType, sendAccountId, mail, expireTime, accountId);
}
}

View File

@@ -0,0 +1,45 @@
using Fantasy;
using Fantasy.Entitas;
using Fantasy.Serialize;
using NB;
using NB.Game;
namespace NBF;
public static class MailFactory
{
/// <summary>
/// 创建一个基础的邮件
/// </summary>
/// <param name="scene"></param>
/// <param name="title"></param>
/// <param name="content"></param>
/// <param name="money"></param>
/// <param name="items"></param>
/// <param name="mailType"></param>
/// <returns></returns>
public static Mail Create(Scene scene, MailType mailType, string title, string content, int money = 0,
List<Item> items = null)
{
var mail = Entity.Create<Mail>(scene, true, true);
mail.Title = title;
mail.Content = content;
mail.Money = money;
mail.MailType = mailType;
mail.MailState = MailState.Unread;
if (items != null && items.Count > 0)
{
foreach (var item in items)
{
// 最好的是要个这个Item给克隆出一份来。
// 这样就可以保证,无论外面怎么改变也不会影响这个邮件的东西了。
var cloneItem = SerializerManager.BsonPack.CloneEntity(item);
mail.Items.Add(cloneItem);
}
}
return mail;
}
}

View File

@@ -0,0 +1,205 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.DataStructure.Collection;
using Fantasy.Platform.Net;
using Fantasy.Serialize;
using NB;
using NB.Game;
namespace NBF;
/// <summary>
/// 发送邮件的唯一接口
/// 如果不是通过这个接口发送的邮件、出现任何问题,后果自负
/// </summary>
public static class MailHelper
{
/// <summary>
/// 发送邮件
/// </summary>
/// <param name="scene"></param>
/// <param name="mailBox">发送完成后记着一定要销毁这个MailBox不然会有GC。</param>
public static async FTask Send(Scene scene, MailBox mailBox)
{
if (scene.SceneType == SceneType.Game)
{
await InnerSend(scene, mailBox);
return;
}
// 如果不在同一个Scene下就需要发送内部的网络消息给这个Scene了
var mailSceneConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Game)[0];
// await scene.NetworkMessagingComponent.CallInnerRoute(mailSceneConfig.RouteId, new Other2Mail_SendMailRequest()
// {
// MailBox = mailBox
// });
scene.NetworkMessagingComponent.Send(mailSceneConfig.Address, new Other2Mail_SendMailRequest()
{
MailBox = mailBox
});
}
/// <summary>
/// 发送邮件
/// </summary>
/// <param name="scene"></param>
/// <param name="mailBox"></param>
/// <returns></returns>
private static async FTask InnerSend(Scene scene, MailBox mailBox)
{
// 现在的情况这个接口只能是在Mail这个服务器下可以操作
// 但是真实的情况,其他同时开发的逻辑,调用这个接口一般都是在其他的服务器。
// 这个问题其实很好解决只需要判定当前Scene不是Mail、那就做一个协议自动发送到这个MailScene就可以了。
if (mailBox.MailBoxType == MailBoxType.None)
{
Log.Error("MailBoxType MailBoxType.None not support!");
return;
}
var playerManageComponent = scene.GetComponent<PlayerManageComponent>();
var mailBoxManageComponent = scene.GetComponent<MailBoxManageComponent>();
mailBoxManageComponent.MailBoxes.Add(mailBox.Id, mailBox);
switch (mailBox.MailBoxType)
{
case MailBoxType.Specify:
{
if (mailBox.AccountId.Count <= 0)
{
Log.Error($"{mailBox.Id} AccountId is 0!");
return;
}
// 这里可能有几种情况
// 1、AccountId里面可能只有一个人。
// 2、AccountId里面有多个人。
using var sendAccountIds = ListPool<long>.Create();
foreach (var accountId in mailBox.AccountId)
{
if (!playerManageComponent.TryGet(accountId, out var mailUnit))
{
// 如果没有的话,代表这个用户根本不存在。
// 那这样的情况就不需要做任何处理。
continue;
}
// 如果有的话,那么就给这个用户发送邮件。
// 这个玩家是否在线?
var mailComponent = mailUnit.GetComponent<MailComponent>();
// 在线的话,就直接发送邮件给这个玩家就可以了。
if (mailComponent != null)
{
await mailComponent.Add(SerializerManager.BsonPack.CloneEntity(mailBox.Mail), true);
sendAccountIds.Add(accountId);
}
else
{
// 不在线
// 首先
// 1、如果玩家不在线那就把这个邮件在数据库中拿出来然后把邮件插入到玩家的邮件列表里。然后再保存
// 这样的做法是不推荐的,因为咱们游戏所有的东西都是有状态的,但是你拿出来的邮件是没有状态的。这样可能会导致一些问题的出现。
// 正确的做做法:
// 把这个邮件方法一个地方,比如是一个处理中心,当玩家上线的时候,主动去这个中心领取这个邮件。
// 快递驿站、菜鸟、
mailBoxManageComponent.MailsByAccount.Add(accountId, mailBox);
Log.Debug("发送离线邮件成功,用户上线第一时间会领取这个邮件。");
}
}
// 移除掉发送成功的账号。
foreach (var sendAccountId in sendAccountIds)
{
mailBox.AccountId.Remove(sendAccountId);
}
// 如果没有任何收件人了、就可以把这个邮箱给删除了。
if (mailBox.AccountId.Count <= 0)
{
mailBox.Dispose();
}
else
{
// 当这个邮件箱还有没有接收的玩家时候,要保存到数据库中,方便下次停服维护再重新启动的时候,加载这个邮件箱。
await scene.World.Database.Save(mailBox);
Log.Debug("保存离线邮件成功");
}
break;
}
case MailBoxType.Online:
{
// // 这里有个问题,如何知道在线的人呢?
// foreach (var (_, mailUnit) in mailUnitManageComponent.UnitByAccountId)
// {
// var mailComponent = mailUnit.GetComponent<MailComponent>();
// if (mailComponent == null)
// {
// continue;
// }
// // 能指定到这里的都是在线的玩家。
// await mailComponent.Add(MailFactory.Serializer.Clone(mailBox.Mail), true);
// }
try
{
foreach (var (_, mailUnit) in playerManageComponent.Players)
{
await mailUnit.GetComponent<MailComponent>()
.Add(SerializerManager.BsonPack.CloneEntity(mailBox.Mail), true);
}
}
finally
{
mailBox.Dispose();
}
break;
}
case MailBoxType.All:
{
// 要保证这个邮件一定要有一个生命周期。并且这个周期一定要短如果是想要实现永久的可以比如30天发送一次。
mailBoxManageComponent.MailsByMailBoxType.Add((int)MailBoxType.All, mailBox);
// 首先给所有在线的玩家发送。
foreach (var (_, mailUnit) in playerManageComponent.Players)
{
await mailUnit.GetComponent<MailComponent>()
.Add(SerializerManager.BsonPack.CloneEntity(mailBox.Mail), true);
// 在邮件盒子中记录下玩家领取的记录,避免重复领取。
mailBox.Received.Add(mailUnit.Id);
}
// 保存邮件箱到数据库。
await scene.World.Database.Save(mailBox);
break;
}
case MailBoxType.AllToDate:
{
mailBoxManageComponent.MailsByMailBoxType.Add((int)MailBoxType.AllToDate, mailBox);
foreach (var (_, player) in playerManageComponent.Players)
{
if (player.CreateTime > mailBox.CreateTime)
{
// 如果执行到这里,表示这里用户是这个邮件创建之后的用户。这个就不要发送了
continue;
}
// 所以这个邮件类型的逻辑就是,给当前邮件创建时间之前的玩家发送。
await player.GetComponent<MailComponent>()
.Add(SerializerManager.BsonPack.CloneEntity(mailBox.Mail), true);
// 在邮件盒子中记录下玩家领取的记录,避免重复领取。
mailBox.Received.Add(player.Id);
}
// 保存邮件箱到数据库。
await scene.World.Database.Save(mailBox);
break;
}
// 根据玩家等级、等等这样的邮件箱类型,都可以自行扩展了
// 课下作业、自己实现一个起来类型的邮箱。
}
}
}

View File

@@ -0,0 +1,230 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.DataStructure.Collection;
using Fantasy.Entitas.Interface;
using Fantasy.Helper;
using Fantasy.Serialize;
using NB;
using NB.Game;
namespace NBF;
public class MailBoxManageComponentDestroySystem : DestroySystem<MailBoxManageComponent>
{
protected override void Destroy(MailBoxManageComponent self)
{
if (self.TimerId != 0)
{
self.Scene.TimerComponent.Net.Remove(ref self.TimerId);
}
foreach (var (_, mailBox) in self.MailBoxes)
{
mailBox.Dispose();
}
self.MinTime = 0;
self.MailsByAccount.Clear();
self.MailsByMailBoxType.Clear();
self.Timers.Clear();
self.TimeOutQueue.Clear();
}
}
public static class MailBoxManageComponentSystem
{
public static async FTask Init(this MailBoxManageComponent self)
{
// 获取数据库中所有的没有处理完成的MailBox
var mailBoxes = await self.Scene.World.Database.Query<MailBox>(d => true);
foreach (var mailBox in mailBoxes)
{
self.MailBoxes.Add(mailBox.Id, mailBox);
switch (mailBox.MailBoxType)
{
case MailBoxType.Specify:
{
foreach (var accountId in mailBox.AccountId)
{
self.MailsByAccount.Add(accountId, mailBox);
}
break;
}
case MailBoxType.All:
case MailBoxType.AllToDate:
{
self.MailsByMailBoxType.Add((int)mailBox.MailBoxType, mailBox);
break;
}
}
}
self.TimerId = self.Scene.TimerComponent.Net.RepeatedTimer(MailBoxManageComponent.MailCheckTIme, self.Timeout);
}
private static void Timeout(this MailBoxManageComponent self)
{
var currentTime = TimeHelper.Now;
if (currentTime < self.MinTime)
{
return;
}
// 检查当然时候有过期的邮件箱需要处理
foreach (var (timeKey, _) in self.Timers)
{
if (timeKey > currentTime)
{
self.MinTime = timeKey;
break;
}
self.TimeOutQueue.Enqueue(timeKey);
}
while (self.TimeOutQueue.TryDequeue(out var timeKey))
{
foreach (var mailBoxId in self.Timers[timeKey])
{
Log.Info($"MailBox:{mailBoxId} 过期了!");
self.Remove(mailBoxId).Coroutine();
}
self.Timers.RemoveKey(timeKey);
}
}
public static async FTask Remove(this MailBoxManageComponent self, long mailBoxId)
{
if (!self.MailBoxes.Remove(mailBoxId, out var mailBox))
{
return;
}
// 先删除按照分类存储的邮箱
self.MailsByMailBoxType.RemoveValue((int)mailBox.MailBoxType, mailBox);
// 删除个人邮件的邮件箱
self.MailsByAccount.RemoveValue(mailBoxId, mailBox);
// 在数据库中删除这个邮件
await self.Scene.World.Database.Remove<MailBox>(mailBoxId);
// 销毁这个MailBox
mailBox.Dispose();
}
public static async FTask GetHaveMail(this MailBoxManageComponent self, Player mailUnit, bool sync)
{
var now = TimeHelper.Now;
var worldDataBase = self.Scene.World.Database;
var mailComponent = mailUnit.GetComponent<MailComponent>();
// 玩家领取范围邮件的逻辑处理
foreach (var (mailBoxType, mailBoxList) in self.MailsByMailBoxType)
{
using var removeMailBox = ListPool<MailBox>.Create();
switch ((MailBoxType)mailBoxType)
{
// 发送给所有人的邮件
case MailBoxType.All:
{
foreach (var mailBox in mailBoxList)
{
if (!mailBox.Received.Contains(mailUnit.Id))
{
// 如果是没有领取过这个邮件,首先要把自己添加到领取过的名单中。
mailBox.Received.Add(mailUnit.Id);
// 发送给自己的邮件列表里添加邮件。
await mailUnit.GetComponent<MailComponent>().Add(SerializerManager.BsonPack.CloneEntity(mailBox.Mail), true);
}
if (mailBox.ExpireTime <= now)
{
// 邮件已经过期了,要进行清理这个邮件的操作了
removeMailBox.Add(mailBox);
continue;
}
// 保存邮件箱状态到数据库中。
await worldDataBase.Save(mailBox);
}
foreach (var mailBox in removeMailBox)
{
await self.Remove(mailBox.Id);
}
// 这里有一个小的细节要处理,这里大家课下自己实现一下。
break;
}
case MailBoxType.AllToDate:
{
foreach (var mailBox in mailBoxList)
{
Log.Debug($"mailBox.CreateTime >= mailUnit.CreateTime {mailBox.CreateTime} >= {mailUnit.CreateTime}");
if (mailBox.CreateTime >= mailUnit.CreateTime && !mailBox.Received.Contains(mailUnit.Id))
{
// 如果是没有领取过这个邮件,首先要把自己添加到领取过的名单中。
mailBox.Received.Add(mailUnit.Id);
// 发送给自己的邮件列表里添加邮件。
await mailUnit.GetComponent<MailComponent>().Add(SerializerManager.BsonPack.CloneEntity(mailBox.Mail), true);
}
if (mailBox.ExpireTime <= now)
{
// 邮件已经过期了,要进行清理这个邮件的操作了
removeMailBox.Add(mailBox);
continue;
}
// 保存邮件箱状态到数据库中。
await worldDataBase.Save(mailBox);
}
foreach (var mailBox in removeMailBox)
{
await self.Remove(mailBox.Id);
}
break;
}
}
}
if (self.MailsByAccount.TryGetValue(mailUnit.Id, out var mailBoxes))
{
using var removeMailBox = ListPool<MailBox>.Create();
foreach (var mailBox in mailBoxes)
{
var cloneMail = SerializerManager.BsonPack.CloneEntity(mailBox.Mail);
await mailComponent.Add(cloneMail, sync);
mailBox.AccountId.Remove(mailUnit.Id);
Log.Debug($"领取了一个离线邮件 MailId:{cloneMail.Id}");
if (mailBox.AccountId.Count <= 0)
{
// 当邮件箱里没有要发送的玩家了,就表示这个邮件箱已经没有用处,可以删除了。
removeMailBox.Add(mailBox);
}
}
foreach (var mailBox in removeMailBox)
{
await self.Remove(mailBox.Id);
}
if (mailBoxes.Count <= 0)
{
// 如果MailsByAccount里的邮件箱已经没有邮件了就删除这个邮件箱的缓存。
self.MailsByAccount.Remove(mailUnit.Id);
}
}
}
}

View File

@@ -1,6 +1,8 @@
using Fantasy.Entitas.Interface;
using Fantasy;
using Fantasy.Entitas.Interface;
using NB;
namespace NB.Chat;
namespace NBF;
public class MailBoxDestroySystem : DestroySystem<MailBox>
{
@@ -12,7 +14,7 @@ public class MailBoxDestroySystem : DestroySystem<MailBox>
self.Mail = null;
}
self.BoxType = MailBoxType.None;
self.MailBoxType = MailBoxType.None;
self.CreateTime = 0;
self.ExpireTime = 0;
self.SendAccountId = 0;

View File

@@ -0,0 +1,234 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.DataStructure.Collection;
using Fantasy.Entitas.Interface;
using Fantasy.Helper;
using NB;
using NB.Game;
namespace NBF;
public class MailComponentDestroySystem : DestroySystem<MailComponent>
{
protected override void Destroy(MailComponent self)
{
foreach (var (_, mail) in self.Mails)
{
mail.Dispose();
}
self.Mails.Clear();
self.Timer.Clear();
}
}
public class MailComponentDeserializeSystem : DeserializeSystem<MailComponent>
{
protected override void Deserialize(MailComponent self)
{
self.Timer.Clear();
foreach (var (_, mail) in self.Mails)
{
self.Timer.Add(mail.ExpireTime, mail.Id);
}
}
}
public static class MailComponentSystem
{
public static async FTask Add(this MailComponent self, Mail mail, bool sync)
{
mail.CreateTime = TimeHelper.Now;
mail.ExpireTime = mail.CreateTime + MailComponent.MailExpireTime;
// 如果身上的邮件数量,大于了设置的最大数量怎么办?
// 先不用考虑,稍后咱们再解决问题。
if (self.Mails.Count >= MailComponent.MaxMailCount)
{
// 删除最老的邮件。
var (_, value) = self.Timer.First();
var removeId = value[0];
await self.Remove(removeId, MailRemoveActionType.Overtop, sync);
}
self.Mails.Add(mail.Id, mail);
self.Timer.Add(mail.ExpireTime, mail.Id);
if (sync)
{
// 同步邮件状态给客户端。
self.Scene.NetworkMessagingComponent.Send(self.GetParent<Player>().SessionRunTimeId,
new Mail2C_HaveMail()
{
Mail = mail.ToMailSimplifyInfo()
});
}
// 这里的保存,也可以不用,这里看情况而定。
await self.Scene.World.Database.Save(self);
Log.Info($"MailComponentSystem Add {mail.Id} Count:{self.Mails.Count}");
}
public static async FTask<uint> Remove(this MailComponent self, long mailId,
MailRemoveActionType mailRemoveActionType, bool sync)
{
if (!self.Mails.Remove(mailId, out var mail))
{
// 这里的1代表的没有找到对应邮件。
return 1;
}
self.Timer.RemoveValue(mail.ExpireTime, mail.Id);
mail.Dispose();
if (sync)
{
// 同步给客户端,邮件删除的消息。
self.Scene.NetworkMessagingComponent.Send(self.GetParent<Player>().SessionRunTimeId,
new Mail2C_MailState()
{
MailState = (int)mailRemoveActionType, MailId = mailId
});
}
// 保存下数据库。
await self.Scene.World.Database.Save(self);
Log.Info(
$"MailComponentSystem Remove {mailId} mailRemoveActionType:{mailRemoveActionType} Count:{self.Mails.Count}");
return 0;
}
public static async FTask CheckTimeOut(this MailComponent self)
{
var now = TimeHelper.Now;
using var listPool = ListPool<long>.Create();
foreach (var (_, mail) in self.Mails)
{
if (mail.ExpireTime > now)
{
continue;
}
listPool.Add(mail.Id);
}
foreach (var mailId in listPool)
{
await self.Remove(mailId, MailRemoveActionType.ExpireTimeRemove, false);
}
Log.Info($"MailComponentSystem CheckTimeOut Count:{listPool.Count}");
}
public static async FTask<(uint ErrorCode, Mail mail)> OpenMail(this MailComponent self, long mailId)
{
if (!self.Mails.TryGetValue(mailId, out var mail))
{
// 这个1代表的是没有找到对应邮件
return (1, null);
}
if (mail.ExpireTime < TimeHelper.Now)
{
// 如果邮件已经过期了,需要清楚这个邮件。
await self.Remove(mailId, MailRemoveActionType.ExpireTimeRemove, true);
// 这里2代表的是邮件已经过期。
return (2, null);
}
mail.MailState = MailState.HaveRead;
// 这个保存数据库不是必须要保存的,因为一个邮件的查看状态并不能影响游戏的逻辑。
// 这里的话,大家看自己的需求而定。
await self.Scene.World.Database.Save(self);
return (0, mail);
}
public static void GetMailSimplifyInfos(this MailComponent self, ICollection<MailSimplifyInfo> mailSimplifyInfos)
{
foreach (var (_, mail) in self.Mails)
{
mailSimplifyInfos.Add(mail.ToMailSimplifyInfo());
}
}
public static void GetMailSimplifyInfos(this MailComponent self, ICollection<MailSimplifyInfo> mailSimplifyInfos,
int pageIndex, int pageSize)
{
foreach (var (_, mail) in self.Mails.Skip((pageIndex - 1) * pageSize).Take(pageSize))
{
mailSimplifyInfos.Add(mail.ToMailSimplifyInfo());
}
}
public static async FTask<uint> Receive(this MailComponent self, long mailId, bool money, List<long> item,
bool sync)
{
if (!self.Mails.TryGetValue(mailId, out var mail))
{
// 这里的1代表是没有找到该邮件。
return 1;
}
var needSave = false;
if (money && mail.Money > 0)
{
// 领取金钱一般都是在玩家身上但现在咱们所在的服务器是Mail服务器玩家并不在这个服务器.
// 所以一般金钱的操作会有一个专用的接口来操作。这个接口无论在什么服务器上,都会正确的发送到用户所在的服务器上进行金钱操作。
// 假设下面的增加金钱的一个异步接口。
// var resposne = await MoneyHelper.Add(self.Scene, mail.Money, sync);
// if (resposne.ErrorCode != 0)
// {
// // 这里的2代表的是金钱添加失败。
// return 2;
// }
// 再假设增加金钱是成功的,那么咱们就要处理邮件相关信息了。
mail.Money = 0;
needSave = true;
}
if (item != null && item.Count > 0)
{
using var listItem = ListPool<Item>.Create();
foreach (var itemId in item)
{
var rItem = mail.Items.FirstOrDefault(d => d.Id == itemId);
if (rItem == null)
{
continue;
}
listItem.Add(rItem);
}
// 假设背包在其他服务器,需要调用某一个接口来添加物品到目标服务器的背包身上。
// var response = await BagHelper.Add(self.Scene, listItem, sync);
// if (response.ErrorCode != 0)
// {
// return 2;
// }
// 还有一种情况就是背包里的空间只有一个空余位置了也就是只能放进一个物品了但是邮件领取的是2个物品.
// 会有下面2中情况,当然这个情况是要策划来决定怎么处理:
// 1、只领取一个物品到背包中另外一个不领取然后提示用户背包已满。
// 2、一个都不领取直接提示用户背包已满。
// 如果是是第一种情况下把BagHelper.Add接口就需要返回添加成功的物品ID方便邮件来处理。
// 假设全部物品都领取成功了,就可以执行下面的逻辑了。
foreach (var item1 in listItem)
{
mail.Items.Remove(item1);
item1.Dispose();
}
needSave = true;
}
if (needSave)
{
await self.Scene.World.Database.Save(self);
}
return 0;
}
}

View File

@@ -0,0 +1,77 @@
using Fantasy;
using Fantasy.Entitas.Interface;
using NB;
namespace NBF;
public sealed class MailDestroySystem : DestroySystem<Mail>
{
protected override void Destroy(Mail self)
{
self.OwnerId = 0;
self.Title = null;
self.Content = null;
self.CreateTime = 0;
self.ExpireTime = 0;
self.Money = 0;
self.MailState = MailState.None;
self.MailType = MailType.None;
foreach (var selfItem in self.Items)
{
selfItem.Dispose();
}
self.Items.Clear();
}
}
public static class MailSystem
{
public static MailSimplifyInfo ToMailSimplifyInfo(this Mail self)
{
return new MailSimplifyInfo()
{
MailId = self.Id,
OwnerId = self.OwnerId,
Title = self.Title,
Content = self.Content,
CreateTime = self.CreateTime,
ExpireTime = self.ExpireTime,
MailState = (int)self.MailState,
MailType = (int)self.MailType
};
}
public static MailInfo ToMailInfo(this Mail self)
{
var mailInfo = new MailInfo()
{
MailId = self.Id,
OwnerId = self.OwnerId,
Title = self.Title,
Content = self.Content,
CreateTime = self.CreateTime,
ExpireTime = self.ExpireTime,
Money = self.Money,
MailState = (int)self.MailState,
MailType = (int)self.MailType
};
foreach (var selfItem in self.Items)
{
mailInfo.Items.Add(new ItemInfo()
{
Id = selfItem.Id,
ConfigId = selfItem.ConfigId,
Count = selfItem.Count,
ExpirationTime = selfItem.ExpirationTime,
GetTime = selfItem.GetTime,
Abrasion = selfItem.Abrasion
});
}
return mailInfo;
}
}

View File

@@ -42,7 +42,6 @@ public static class RoomManageComponentSystem
return null;
}
// roomManageComponent.on
var room = Entity.Create<MapRoom>(self.Scene, true, true);
room.Owner = ownerId;
room.RoomId = roomId;

View File

@@ -91,7 +91,7 @@ public static class PlayerManageComponentSystem
return null;
}
}
// account.Statistics.LoginTime = TimeHelper.Now;
// account.SetTestData();
@@ -157,6 +157,7 @@ public static class PlayerManageComponentSystem
player.Country = "cn";
player.Exp = 999;
player.Head = "xxx.png";
player.CreateTime = TimeHelper.Now;
// var list = InitConfig.GetList();
var list = Configs.Tables.TbInitItemConfig.DataList;

View File

@@ -5,6 +5,7 @@ using Fantasy.Async;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using Fantasy.Helper;
using NB.Chat;
#pragma warning disable CS8625 // 无法将 null 字面量转换为非 null 的引用类型。
@@ -31,6 +32,16 @@ public sealed class PlayerDestroySystem : DestroySystem<Player>
// self.Statistics.Dispose();
// self.Statistics = null;
// 退出当前ChatUnit拥有的所有频道
foreach (var (_, chatChannelComponent) in self.Channels)
{
chatChannelComponent.ExitChannel(self.Id, false);
}
// 理论情况下这个self.Channels不会存在因为数据的因为上面已经给清空掉了。
// 但是self.Channels.Clear();还是加上吧,防止以后忘记了。
self.Channels.Clear();
self.SessionRunTimeId = 0;
}
}
@@ -47,7 +58,6 @@ public static class PlayerSystem
/// <param name="items"></param>
public static async FTask AddItems(this Player self, Dictionary<int, int> items)
{
var itemContainer = self.GetComponent<PlayerItemContainerComponent>();
HashSet<ItemBasicType> addType = new HashSet<ItemBasicType>();
foreach (var (key, value) in items)
@@ -64,7 +74,7 @@ public static class PlayerSystem
}
#endregion
public static MapUnitInfo ToMapUnitInfo(this Player self)
{
var ret = new MapUnitInfo()
@@ -79,11 +89,11 @@ public static class PlayerSystem
ret.Position.x = mapUnit.Position.x;
ret.Position.y = mapUnit.Position.y;
ret.Position.z = mapUnit.Position.z;
ret.Rotation.x = mapUnit.Rotation.x;
ret.Rotation.y = mapUnit.Rotation.y;
ret.Rotation.z = mapUnit.Rotation.z;
// ret.Gears
return ret;

View File

@@ -1,46 +0,0 @@
using System;
using Fantasy;
using Fantasy.Async;
using Fantasy.Network.Interface;
using NB.Game;
namespace NB.Chat;
public class C2Game_DeleteMailRequestHandler : AddressRPC<Player, C2Game_DeleteMailRequest, Game2C_DeleteMailResponse>
{
protected override async FTask Run(Player entity, C2Game_DeleteMailRequest request,
Game2C_DeleteMailResponse response, Action reply)
{
if (request.Id < 1)
{
response.ErrorCode = ErrorCode.ErrArgs;
return;
}
var mailManageComponent = entity.Scene.GetComponent<MailManageComponent>();
if (mailManageComponent == null)
{
Log.Error("组件不存在 MailManageComponent");
response.ErrorCode = ErrorCode.ErrServer;
return;
}
var conversation = await mailManageComponent.GetConversation(entity.Id, request.Id);
if (conversation == null)
{
response.ErrorCode = ErrorCode.ErrArgs;
return;
}
conversation.RemoveId.Add(entity.Id);
if (conversation.RemoveId.Count > 1)
{
//都删除了,则吧会话直接移除掉
await mailManageComponent.DeleteConversation(entity.Id, request.Id);
}
else
{
await conversation.Save();
}
}
}

View File

@@ -1,24 +0,0 @@
using System;
using System.Diagnostics;
using Fantasy;
using Fantasy.Async;
using Fantasy.Network.Interface;
using NB.Game;
namespace NB.Chat;
public class
C2Game_GetConversationsRequestHandler : AddressRPC<Player, C2Game_GetConversationsRequest, Game2C_GetConversationsResponse>
{
protected override async FTask Run(Player entity, C2Game_GetConversationsRequest request,
Game2C_GetConversationsResponse response, Action reply)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
var mailManageComponent = entity.Scene.GetComponent<MailManageComponent>();
var list = await mailManageComponent.GetConversations(entity.Id);
response.List = await list.ToInfo(entity.Scene, entity.Id);
stopwatch.Stop();
Log.Info($"查询会话列表耗时={stopwatch.ElapsedMilliseconds}");
}
}

View File

@@ -1,70 +0,0 @@
using System;
using Fantasy;
using Fantasy.Async;
using Fantasy.Network.Interface;
using NB.Game;
namespace NB.Chat;
public class C2Game_SendMailRequestHandler : AddressRPC<Player, C2Game_SendMailRequest, Game2C_SendMailResponse>
{
protected override async FTask Run(Player entity, C2Game_SendMailRequest request, Game2C_SendMailResponse response,
Action reply)
{
if (request.Target < 1)
{
response.ErrorCode = ErrorCode.ErrArgs;
return;
}
var mailManageComponent = entity.Scene.GetComponent<MailManageComponent>();
if (mailManageComponent == null)
{
Log.Error("组件不存在 MailManageComponent");
response.ErrorCode = ErrorCode.ErrServer;
return;
}
var chatUnitManage = entity.Scene.GetComponent<PlayerManageComponent>();
if (chatUnitManage == null)
{
Log.Error("组件不存在 SocialUnitManageComponent");
response.ErrorCode = ErrorCode.ErrServer;
return;
}
var conversation = await mailManageComponent.GetConversation(entity.Id, request.Target);
if (conversation == null)
{
response.ErrorCode = ErrorCode.ErrArgs;
return;
}
//检查是否可以发消息,如果会话只有一句,则不允许再发
if (!conversation.CanSend(entity.Id))
{
response.ErrorCode = ErrorCode.MailNotReply;
return;
}
var mail = MailFactory.Create(entity.Scene, request.Content);
mail.Sender = entity.Id;
mail.OwnerId = request.Target;
await conversation.Add(mail);
var res = new Game2C_HaveMail()
{
Mail = mail.ToMailInfo(),
Key = conversation.Key
};
//同步客户端
entity.Scene.NetworkMessagingComponent.Send(entity.SessionRunTimeId, res);
// var chatUnit = chatUnitManage.Get(request.Target);
//
// if (chatUnit != null)
// {
// //对方在线
// entity.Scene.NetworkMessagingComponent.Send(chatUnit.GateRouteId, res);
// }
}
}

View File

@@ -1,56 +0,0 @@
using System.Collections.Generic;
using Fantasy;
using Fantasy.Entitas;
using Fantasy.Helper;
using NB.Game;
namespace NB.Chat;
public static class MailBoxFactory
{
/// <summary>
/// 创建一个邮件箱
/// </summary>
/// <param name="scene"></param>
/// <param name="sendAccountId"></param>
/// <param name="mail"></param>
/// <param name="expireTime"></param>
/// <param name="accountIds"></param>
/// <returns></returns>
public static MailBox Create(Scene scene, long sendAccountId, Mail mail, int expireTime, List<long> accountIds)
{
var mailBox = Entity.Create<MailBox>(scene, true, true);
mailBox.SendAccountId = sendAccountId;
mailBox.Mail = mail;
mailBox.ExpireTime = TimeHelper.Now + expireTime;
mailBox.CreateTime = TimeHelper.Now;
if (accountIds == null || accountIds.Count <= 0)
{
return mailBox;
}
foreach (var accountId in accountIds)
{
mailBox.AccountId.Add(accountId);
}
return mailBox;
}
/// <summary>
/// 创建一个邮件箱
/// </summary>
/// <param name="scene"></param>
/// <param name="sendAccountId"></param>
/// <param name="expireTime"></param>
/// <param name="accountIds"></param>
/// <param name="content"></param>
/// <param name="items"></param>
/// <returns></returns>
public static MailBox Create(Scene scene, long sendAccountId, int expireTime, List<long> accountIds,
string content, List<AwardItem> items = null)
{
var mail = MailFactory.Create(scene, content, items);
return Create(scene, sendAccountId, mail, expireTime, accountIds);
}
}

View File

@@ -1,38 +0,0 @@
using Fantasy;
using Fantasy.Async;
using NB.Game;
namespace NB.Chat;
public static class MailConversationHelper
{
/// <summary>
/// 从数据库中读取GameAccount
/// </summary>
/// <param name="scene"></param>
/// <param name="firstId"></param>
/// <param name="secondId"></param>
/// <returns></returns>
public static async FTask<MailConversation> LoadDataBase(Scene scene, long firstId, long secondId)
{
var conversation =
await scene.World.Database.First<MailConversation>(d => d.FirstId == firstId && d.SecondId == secondId);
if (conversation == null)
{
return null;
}
conversation.Deserialize(scene);
return conversation;
}
/// <summary>
/// 从数据库中移除
/// </summary>
/// <param name="scene"></param>
/// <param name="id"></param>
public static async FTask DeleteDataBase(Scene scene,long id)
{
await scene.World.Database.Remove<MailConversation>(id);
}
}

View File

@@ -1,32 +0,0 @@
using System.Collections.Generic;
using Fantasy;
using Fantasy.Entitas;
using Fantasy.Helper;
using Fantasy.Serialize;
using NB.Game;
namespace NB.Chat;
public static class MailFactory
{
private static readonly ISerialize _serializer = SerializerManager.BsonPack;
public static Mail Create(Scene scene, string content, List<AwardItem> items = null)
{
var mail = Entity.Create<Mail>(scene, true, true);
mail.Content = content;
mail.State = MailState.Unread;
mail.CreateTime = TimeHelper.Now;
if (items != null && items.Count > 0)
{
foreach (var item in items)
{
// mail.Items.Add(_serializer.Clone(item));
}
}
return mail;
}
}

View File

@@ -1,32 +0,0 @@
using Fantasy;
using Fantasy.Async;
namespace NB.Chat;
/// <summary>
/// 发送邮件接口
/// </summary>
public static class MailHelper
{
public static async FTask Send(Scene scene, MailBox mailBox)
{
if (mailBox.BoxType == MailBoxType.None)
{
Log.Error("不支持的邮件类型");
return;
}
switch (mailBox.BoxType)
{
case MailBoxType.All:
{
break;
}
case MailBoxType.Specify:
{
break;
}
}
}
}

View File

@@ -1,80 +0,0 @@
using System.Linq;
using Fantasy;
using Fantasy.Async;
using Fantasy.Entitas.Interface;
using Fantasy.Helper;
namespace NB.Chat;
public class MailComponentDestroySystem : DestroySystem<MailComponent>
{
protected override void Destroy(MailComponent self)
{
foreach (var (_, mail) in self.Mails)
{
mail.Dispose();
}
self.Mails.Clear();
self.Timer.Clear();
}
}
public static class MailComponentSystem
{
public static async FTask Add(this MailComponent self, Mail mail, bool sync)
{
mail.CreateTime = TimeHelper.Now;
mail.ExpireTime = TimeHelper.Now + MailComponent.MaxExpireTime;
if (self.Mails.Count >= MailComponent.MaxMailCount)
{
//删除最老的邮件
var (_, value) = self.Timer.First();
foreach (var removeId in value)
{
await self.Remove(removeId, sync);
}
}
self.Mails.Add(mail.Id, mail);
self.Timer.Add(mail.ExpireTime, mail.Id);
if (sync)
{
//同步客户端
self.Scene.NetworkMessagingComponent.Send(0,new Game2C_HaveMail()
{
Mail = mail.ToMailInfo(),
});
}
await self.Scene.World.Database.Save(self);
Log.Info($"MailComponent Add id:{self.Id} mailId:{mail.Id} count:{self.Mails.Count}");
}
public static async FTask<uint> Remove(this MailComponent self, long mailId, bool sync)
{
if (!self.Mails.Remove(mailId, out var mail))
{
return 1;
}
self.Timer.RemoveValue(mail.ExpireTime, mail.Id);
mail.Dispose();
if (sync)
{
//同步客户端
self.Scene.NetworkMessagingComponent.Send(0,new Game2C_MailState()
{
MailState = (int)MailState.Deleted,
MailId = mailId,
});
}
await self.Scene.World.Database.Save(self);
Log.Info($"MailComponent Remove id:{self.Id} mailId:{mail.Id} count:{self.Mails.Count}");
return 0;
}
}

View File

@@ -1,128 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Fantasy;
using Fantasy.Async;
using Fantasy.Entitas.Interface;
using Fantasy.Helper;
using NB.Game;
namespace NB.Chat;
public class MailConversationDeserializeSystem : DeserializeSystem<MailConversation>
{
protected override void Deserialize(MailConversation self)
{
self.Key = $"{self.FirstId}-{self.SecondId}";
}
}
public class MailConversationDestroySystem : DestroySystem<MailConversation>
{
protected override void Destroy(MailConversation self)
{
foreach (var mail in self.Mails)
{
mail.Dispose();
}
self.Mails.Clear();
self.FirstId = 0;
self.SecondId = 0;
self.Key = string.Empty;
}
}
public static class MailConversationSystem
{
public static async FTask Add(this MailConversation self, Mail mail)
{
self.Mails.Add(mail);
if (self.Mails.Count > AppConfig.MaxConversationCount)
{
self.Mails.RemoveAt(0);
}
if (mail.Items != null && mail.Items.Count > 0)
{
//有附件需要立马保存
await self.Save(true);
}
else
{
await self.Save(false);
}
}
public static async FTask Save(this MailConversation self, bool forceSave = true)
{
// self.NeedSave = true;
// self.NeedSaveTime = TimeHelper.Now + AppConfig.PlayerDataAutoSaveTime;
if (forceSave)
{
self.UpdateTime = TimeHelper.Now;
await self.Scene.World.Database.Save(self);
}
else
{
self.NeedSave = true;
self.NeedSaveTime = TimeHelper.Now + AppConfig.ChatDataAutoSaveTime;
}
}
/// <summary>
/// 是否可以发送邮件
/// </summary>
/// <param name="self"></param>
/// <param name="sendId"></param>
/// <returns></returns>
public static bool CanSend(this MailConversation self, long sendId)
{
if (self.Mails.Count < 1) return true;
foreach (var mail in self.Mails)
{
if (mail.Sender != sendId)
{
return true;
}
}
return false;
}
#region
public static async FTask<List<ConversationInfo>> ToInfo(this List<MailConversation> self, Scene scene, long selfId)
{
List<ConversationInfo> ret = new List<ConversationInfo>();
HashSet<long> ids = new HashSet<long>();
foreach (var conversation in self)
{
if (conversation.RemoveId.Contains(selfId)) continue;
ids.Add(conversation.FirstId);
ids.Add(conversation.SecondId);
}
ids.Remove(selfId);
var infos = await CacheHandler.GetPlayerBasicCacheInfos(scene, ids.ToList());
foreach (var conversation in self)
{
if (conversation.RemoveId.Contains(selfId)) continue;
var item = new ConversationInfo();
item.List = conversation.Mails.ToMailInfo();
var otherId = conversation.FirstId == selfId ? conversation.SecondId : conversation.FirstId;
var info = infos.Find(t => t.RoleId == otherId);
if (info != null)
{
item.RoleInfo = info;
}
ret.Add(item);
}
return ret;
}
#endregion
}

View File

@@ -1,94 +0,0 @@
using System.Collections.Generic;
using Fantasy;
using Fantasy.Async;
using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
using Fantasy.Helper;
using NB.Game;
namespace NB.Chat;
public class MailManageComponentDestroySystem : DestroySystem<MailManageComponent>
{
protected override void Destroy(MailManageComponent self)
{
foreach (var (_, conversation) in self.Conversations)
{
conversation.Dispose();
}
self.Conversations.Clear();
}
}
public static class MailManageComponentSystem
{
public static async FTask DeleteConversation(this MailManageComponent self, long selfId, long otherId)
{
var firstId = selfId;
var secondId = otherId;
if (otherId < selfId)
{
firstId = otherId;
secondId = selfId;
}
var key = $"{firstId}-{secondId}";
if (self.Conversations.Remove(key, out var conversation))
{
await MailConversationHelper.DeleteDataBase(conversation.Scene, conversation.Id);
conversation.Dispose();
}
}
public static async FTask<MailConversation?> GetConversation(this MailManageComponent self, long selfId,
long otherId)
{
var firstId = selfId;
var secondId = otherId;
if (otherId < selfId)
{
firstId = otherId;
secondId = selfId;
}
var key = $"{firstId}-{secondId}";
if (!self.Conversations.TryGetValue(key, out var conversation))
{
//检查数据库中是否存在
conversation = await MailConversationHelper.LoadDataBase(self.Scene, firstId, secondId);
if (conversation == null)
{
//检查id是否合法
var roleInfo = await CacheHandler.GetPlayerBasicCacheInfo(self.Scene, otherId);
if (roleInfo == null)
{
return null;
}
conversation = Entity.Create<MailConversation>(self.Scene, true, true);
conversation.FirstId = firstId;
conversation.SecondId = secondId;
conversation.Key = key;
await conversation.Save(false);
}
self.Conversations.Add(key, conversation);
}
return conversation;
}
public static async FTask<List<MailConversation>> GetConversations(this MailManageComponent self, long id)
{
List<MailConversation> players =
await self.Scene.World.Database.QueryByPageOrderBy<MailConversation>(
d => d.FirstId == id || d.SecondId == id, 1, 50,
d => d.UpdateTime);
return players;
}
}

View File

@@ -1,53 +0,0 @@
using System.Collections.Generic;
using Fantasy;
using Fantasy.Entitas.Interface;
using NB.Game;
namespace NB.Chat;
public class MailDestroySystem : DestroySystem<Mail>
{
protected override void Destroy(Mail self)
{
self.OwnerId = 0;
self.Sender = 0;
self.Content = string.Empty;
self.ExpireTime = 0;
self.CreateTime = 0;
self.State = MailState.None;
self.MailType = MailType.None;
foreach (var item in self.Items)
{
item.Dispose();
}
self.Items.Clear();
}
}
public static class MailSystem
{
public static MailInfo ToMailInfo(this Mail mail)
{
return new MailInfo()
{
Id = mail.Id,
Content = mail.Content,
CreateTime = mail.CreateTime,
MailState = (int)mail.State,
MailType = (int)mail.MailType,
Items = mail.Items.ToAwardInfo()
};
}
public static List<MailInfo> ToMailInfo(this List<Mail> mails)
{
var list = new List<MailInfo>();
foreach (var mail in mails)
{
list.Add(mail.ToMailInfo());
}
return list;
}
}

View File

@@ -1,146 +0,0 @@
// using Fantasy;
// using Fantasy.Async;
// using Fantasy.Entitas;
// using Fantasy.Entitas.Interface;
// using NB.Chat;
//
// namespace NBF.Social;
//
// public sealed class ChatUnitManageComponentDestroySystem : DestroySystem<SocialUnitManageComponent>
// {
// protected override void Destroy(SocialUnitManageComponent self)
// {
// foreach (var chatUnit in self.Units.Values.ToArray())
// {
// chatUnit.Dispose();
// }
//
// self.Units.Clear();
// }
// }
//
// public static class SocialUnitManageComponentSystem
// {
// #region 消息缓存
//
// /// <summary>
// /// 离线消息,进入待领取队列
// /// </summary>
// /// <param name="self"></param>
// /// <param name="targetId"></param>
// /// <param name="message"></param>
// public static void SaveOfflineMessage(this SocialUnitManageComponent self, long targetId, ChatMessageInfo message)
// {
// // self.NotSendMessage.Add(targetId, message);
// }
//
// #endregion
//
// #region 上线下线
//
// /// <summary>
// /// 玩家上线
// /// </summary>
// /// <param name="self"></param>
// /// <param name="scene"></param>
// /// <param name="accountId"></param>
// /// <param name="gateRouteId"></param>
// public static async FTask<SocialUnit?> Online(this SocialUnitManageComponent self, Scene scene,
// long accountId,
// long gateRouteId)
// {
// // var accountId = roleSimpleInfo.RoleId;
// if (!self.TryGet(accountId, out var account))
// {
// account = Entity.Create<SocialUnit>(scene, accountId, true, true);
// self.Add(account);
// }
//
// if (account != null)
// {
// await account.TryComponent<MailComponent>();
// account.GateRouteId = gateRouteId;
// // account.Role = roleSimpleInfo;
// }
//
// await FTask.CompletedTask;
// return account;
// }
//
// public static async FTask Offline(this SocialUnitManageComponent self, Scene scene, long accountId,
// long gateRouteId)
// {
// if (self.TryGet(accountId, out var unit) && unit != null)
// {
// if (unit.GateRouteId == gateRouteId)
// {
// Log.Info("退出当前聊天服==");
// self.Remove(accountId); //如果当前网关和下线的网关一致
// }
// }
//
// await FTask.CompletedTask;
// }
//
// #endregion
//
// #region 获取&移除
//
// public static void Add(this SocialUnitManageComponent self, SocialUnit account)
// {
// self.Units.Add(account.Id, account);
// }
//
// public static SocialUnit? Get(this SocialUnitManageComponent self, long accountId)
// {
// return self.Units.GetValueOrDefault(accountId);
// }
//
// public static bool TryGet(this SocialUnitManageComponent self, long accountId, out SocialUnit? account)
// {
// return self.Units.TryGetValue(accountId, out account);
// }
//
// public static void Remove(this SocialUnitManageComponent self, long accountId, bool isDispose = true)
// {
// if (!self.Units.Remove(accountId, out var account))
// {
// return;
// }
//
// if (!isDispose)
// {
// return;
// }
//
// account.Dispose();
// }
//
// #endregion
//
// #region 组件
//
// /// <summary>
// /// 尝试给增加相关组件
// /// </summary>
// /// <param name="socialUnit"></param>
// /// <typeparam name="T"></typeparam>
// public static async FTask TryComponent<T>(this SocialUnit socialUnit) where T : Entity, new()
// {
// if (socialUnit.GetComponent<T>() == null)
// {
// var mailComponent = await socialUnit.Scene.World.Database.Query<T>(socialUnit.Id, true);
// if (mailComponent == null)
// {
// //如果没有邮件组件
// socialUnit.AddComponent<T>();
// }
// else
// {
// socialUnit.AddComponent(mailComponent);
// }
// }
// }
//
// #endregion
// }

View File

@@ -1,22 +0,0 @@
// using Fantasy.Entitas.Interface;
// #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
//
// namespace NB.Chat;
//
// public sealed class SocialUnitDestroySystem : DestroySystem<SocialUnit>
// {
// protected override void Destroy(SocialUnit self)
// {
// self.Role?.Return();
// self.Role = null;
// self.GateRouteId = 0;
// // 退出当前ChatUnit拥有的所有频道
// foreach (var (_,chatChannelComponent) in self.Channels)
// {
// chatChannelComponent.ExitChannel(self.Id, false);
// }
// // 理论情况下这个self.Channels不会存在因为数据的因为上面已经给清空掉了。
// // 但是self.Channels.Clear();还是加上吧,防止以后忘记了。
// self.Channels.Clear();
// }
// }

View File

@@ -12,4 +12,9 @@
<ProjectReference Include="..\Entity\Entity.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Game\Condition\" />
<Folder Include="Game\Mail\Handler\" />
</ItemGroup>
</Project>

View File

@@ -138,10 +138,9 @@ public sealed class OnCreateSceneEvent : AsyncEventSystem<OnCreateScene>
private async FTask InitializeSocialScene(Scene scene)
{
Log.Info($"初始化 Social 场景: {scene.Id}");
//用于管理玩家的组件
scene.AddComponent<MailManageComponent>();
//聊天
// Log.Info($"初始化 Social 场景: {scene.Id}");
// 离线邮件箱管理组件
await scene.AddComponent<MailBoxManageComponent>().Init();
// 聊天频道中控中心组件。
scene.AddComponent<ChatChannelCenterComponent>();
await FTask.CompletedTask;
@@ -154,7 +153,7 @@ public sealed class OnCreateSceneEvent : AsyncEventSystem<OnCreateScene>
//用于管理玩家的组件
scene.AddComponent<PlayerManageComponent>();
scene.AddComponent<PlayerBasicCacheManageComponent>();
await scene.AddComponent<ItemUseComponent>().Initialize();
Log.Info("创建地图场景===");
var roomManageComponent = scene.AddComponent<RoomManageComponent>();

View File

@@ -66,5 +66,8 @@
<None Update="cfg\tbshop.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="cfg\tbleader.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -4,27 +4,31 @@
"name": "鲤鱼",
"min_weight": 1,
"max_weight": 34,
"accept": 2100001
"accept": 2100001,
"water": 0
},
{
"id": 210002,
"name": "金鲫",
"min_weight": 1,
"max_weight": 34,
"accept": 2100001
"accept": 2100001,
"water": 0
},
{
"id": 210003,
"name": "银鲫",
"min_weight": 1,
"max_weight": 34,
"accept": 2100001
"accept": 2100001,
"water": 0
},
{
"id": 210004,
"name": "拟鲤",
"min_weight": 1,
"max_weight": 34,
"accept": 2100001
"accept": 2100001,
"water": 0
}
]

View File

@@ -8,6 +8,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -20,6 +21,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -32,6 +34,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -44,6 +47,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -56,6 +60,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -68,6 +73,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -80,6 +86,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -92,6 +99,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -104,6 +112,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -116,6 +125,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -128,6 +138,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -140,6 +151,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -152,6 +164,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -164,6 +177,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -176,6 +190,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -188,6 +203,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -200,6 +216,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -212,6 +229,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -224,6 +242,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -236,6 +255,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -248,6 +268,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -260,6 +281,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -272,6 +294,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -284,6 +307,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -296,6 +320,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -308,6 +333,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -320,6 +346,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -332,6 +359,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -344,6 +372,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -356,6 +385,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -368,6 +398,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -380,6 +411,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -392,6 +424,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -404,6 +437,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -416,6 +450,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -428,6 +463,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -440,6 +476,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -452,6 +489,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -464,6 +502,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -476,6 +515,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -488,6 +528,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -500,6 +541,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -512,6 +554,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -524,6 +567,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -536,6 +580,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -548,6 +593,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -560,6 +606,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -572,6 +619,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -584,6 +632,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -596,6 +645,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -608,6 +658,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -620,6 +671,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -632,6 +684,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -644,6 +697,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -656,6 +710,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -668,6 +723,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -680,6 +736,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -692,6 +749,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -704,6 +762,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -716,6 +775,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -728,6 +788,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -740,6 +801,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -752,6 +814,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -764,6 +827,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -776,6 +840,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -788,6 +853,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -800,6 +866,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -812,6 +879,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -824,6 +892,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -836,6 +905,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -848,6 +918,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -860,6 +931,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -872,6 +944,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -884,6 +957,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -896,6 +970,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -908,6 +983,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -920,6 +996,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -932,6 +1009,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -944,6 +1022,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -956,6 +1035,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -968,6 +1048,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -980,6 +1061,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -992,6 +1074,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -1004,6 +1087,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -1016,6 +1100,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -1028,6 +1113,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -1040,6 +1126,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -1052,6 +1139,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -1064,6 +1152,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -1076,6 +1165,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -1088,6 +1178,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -1100,6 +1191,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
},
@@ -1112,6 +1204,7 @@
"length": 0,
"max": 0,
"auto_use": 0,
"effect": 0,
"result1": [],
"result2": []
}

12
Main/cfg/tbleader.json Normal file
View File

@@ -0,0 +1,12 @@
[
{
"id": 60001,
"strength": 40,
"size": 1
},
{
"id": 60002,
"strength": 40,
"size": 1
}
]

View File

@@ -4,13 +4,20 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAssemblyLoadContext_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb241c378a97f4447a2e6baf64e656013e8e910_003F96_003Fd3906b05_003FAssemblyLoadContext_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAssembly_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb241c378a97f4447a2e6baf64e656013e8e910_003F9f_003Fab186807_003FAssembly_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAwakeSystem_00601_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3cbbaf32e578423d8d0163d75da8233f87e00_003Fd6_003F72740830_003FAwakeSystem_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABsonPackHelper_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F199e3c534d1e41cbb9a3a30bbf9ac93bde200_003Fa9_003F662c90bf_003FBsonPackHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADestroySystem_00601_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3cbbaf32e578423d8d0163d75da8233f87e00_003Fbd_003Fcd9cb7f1_003FDestroySystem_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADictionary_00602_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F76803a04e31b4fee99d90bcbfc5a6bdde8e930_003F33_003F170c5f2b_003FDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEntity_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F199e3c534d1e41cbb9a3a30bbf9ac93bde200_003F7f_003F8a76c302_003FEntity_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEntry_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F199e3c534d1e41cbb9a3a30bbf9ac93bde200_003F31_003Fd222e398_003FEntry_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIAssemblyLifecycle_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F199e3c534d1e41cbb9a3a30bbf9ac93bde200_003F2f_003F523cab0e_003FIAssemblyLifecycle_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIProtoParser_00601_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F199e3c534d1e41cbb9a3a30bbf9ac93bde200_003Fcc_003Fc5b3dd8c_003FIProtoParser_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AISerialize_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F199e3c534d1e41cbb9a3a30bbf9ac93bde200_003F7d_003F9fe3ad36_003FISerialize_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AList_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F1b81cb3be224213a6a73519b6e340a628d9a1fb8629c351a186a26f6376669_003FList_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemoryPackableAttribute_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fba5a62274184491dacbff186935d11a833600_003F72_003F6c6d24a2_003FMemoryPackableAttribute_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANetworkMessagingComponent_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5935efc3ba8745d5800392d88681b8c2ddc00_003Fdd_003Fc26349d0_003FNetworkMessagingComponent_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANetworkMessagingComponent_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F199e3c534d1e41cbb9a3a30bbf9ac93bde200_003F6d_003F2f2e114c_003FNetworkMessagingComponent_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AOneToManyList_00602_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F199e3c534d1e41cbb9a3a30bbf9ac93bde200_003F6a_003Fd828fa89_003FOneToManyList_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AProcessMode_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F199e3c534d1e41cbb9a3a30bbf9ac93bde200_003F23_003F78c782e6_003FProcessMode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AScene_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3cbbaf32e578423d8d0163d75da8233f87e00_003F6a_003F5adfe93e_003FScene_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASerializerManager_002Ecs_002Fl_003AC_0021_003FUsers_003FFIREBAT_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F199e3c534d1e41cbb9a3a30bbf9ac93bde200_003F9f_003Fa4f53cf4_003FSerializerManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASortedOneToManyList_00602_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3cbbaf32e578423d8d0163d75da8233f87e00_003F12_003Fcfa98068_003FSortedOneToManyList_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>

View File

@@ -98,3 +98,14 @@ message Other2Chat_ChatMessage // IAddressMessage
ChatInfoTree ChatInfoTree = 1;
}
////////////// ******** 邮件 *******/////////////
/// 其他服务器发送邮件
// Protocol Bson
message Other2Mail_SendMailRequest // IAddressRequest,Mail2Other_SendMailResponse
{
MailBox MailBox = 1;
}
message Mail2Other_SendMailResponse // IAddressResponse
{
}

View File

@@ -0,0 +1,102 @@
syntax = "proto3";
package Fantasy.Network.Message;
/// 测试Mail自定义Route协议
message C2Mail_TestRequest // ICustomRouteRequest,Mail2C_TestResponse,GameRoute
{
string Tag = 1;
}
message Mail2C_TestResponse // ICustomRouteResponse
{
string Tag = 1;
}
/// 一个邮件的完整信息
message MailInfo
{
int64 MailId = 1;
int64 OwnerId = 2;
string Title = 3;
string Content = 4;
int64 CreateTime = 5;
int64 ExpireTime = 6;
int32 Money = 7;
int32 MailState = 8;
int32 MailType = 9;
repeated ItemInfo Items = 10;
}
/// 一个邮件的简单版消息
message MailSimplifyInfo
{
int64 MailId = 1;
int64 OwnerId = 2;
string Title = 3;
string Content = 4;
int64 CreateTime = 5;
int64 ExpireTime = 6;
int32 MailState = 7;
int32 MailType = 8;
}
/// Mail通知客户端有新的邮件
message Mail2C_HaveMail // ICustomRouteMessage,GameRoute
{
MailSimplifyInfo Mail = 1;
}
/// Mail通知客户端邮件状态变化
message Mail2C_MailState // ICustomRouteMessage,GameRoute
{
int32 MailState = 1;
int64 MailId = 2;
}
/// 客户端获取档期所有邮件的信息
message C2Mail_GetHaveMailRequest // ICustomRouteRequest,Mail2C_GetHaveMailResposne,GameRoute
{
}
message Mail2C_GetHaveMailResposne // ICustomRouteResponse
{
repeated MailSimplifyInfo Mails = 1;
}
/// 客户端发开一个邮件
message C2Mail_OpenMailRequest // ICustomRouteRequest,Mail2C_OpenMailResposne,GameRoute
{
int64 MailId = 1;
bool ReturnMailInfo = 2;
}
message Mail2C_OpenMailResposne // ICustomRouteResponse
{
MailInfo MailInfo = 1;
}
/// 客户端领取邮件的附件
message C2Mail_ReceiveMailRequest // ICustomRouteRequest,Mail2C_ReceiveMailResponse,GameRoute
{
int64 MailId = 1;
bool Money = 2;
repeated int64 ItemId = 3;
}
message Mail2C_ReceiveMailResponse // ICustomRouteResponse
{
}
/// 客户端通知服务器删除一个邮件
message C2Mail_RemoveMailRequest // ICustomRouteRequest,Mail2C_RemoveMailResponse,GameRoute
{
int64 MailId = 1;
}
message Mail2C_RemoveMailResponse // ICustomRouteResponse
{
}
/// 客户端玩家发送邮件到另外一个玩家
message C2Mail_SendMailRequest // ICustomRouteRequest,Mail2C_SendMailResponse,GameRoute
{
int64 UserId = 1;
string Title = 2;
string Content = 3;
int32 Money = 4;
repeated int64 ItemId = 5;
}
message Mail2C_SendMailResponse // ICustomRouteResponse
{
}

View File

@@ -1,79 +1,6 @@
syntax = "proto3";
package Fantasy.Network.Message;
////////////// ******** 私聊/邮件 *******/////////////
/// 会话信息
message ConversationInfo
{
RoleSimpleInfo RoleInfo = 1; //对方信息
repeated MailInfo List = 2;//对话列表
}
message MailInfo
{
int64 Id = 1; //邮件id
int64 Sender = 2; //发送者
string Content = 3; //内容
int64 CreateTime = 4; //发送时间
int32 MailType = 5; //邮件类型
int32 MailState = 6; //邮件状态
repeated AwardInfo Items = 7; //附件列表
}
///请求会话列表
message C2Game_GetConversationsRequest // ICustomRouteRequest,Game2C_GetConversationsResponse,GameRoute
{
}
///请求会话列表响应
message Game2C_GetConversationsResponse // ICustomRouteResponse
{
repeated ConversationInfo List = 1;
}
///发送邮件消息
message C2Game_SendMailRequest // ICustomRouteRequest,Game2C_SendMailResponse,GameRoute
{
int64 Target = 1; //目标id
string Content = 2; //内容
repeated AwardInfo Items = 3; //附件列表
}
///发送邮件消息响应
message Game2C_SendMailResponse // ICustomRouteResponse
{
}
///发送删除会话消息
message C2Game_DeleteMailRequest // ICustomRouteRequest,Game2C_DeleteMailResponse,GameRoute
{
int64 Id = 1; //会话id
}
///发送删除会话消息响应
message Game2C_DeleteMailResponse // ICustomRouteResponse
{
int64 Id = 1; //会话id
}
///新邮件推送
message Game2C_HaveMail // ICustomRouteMessage,GameRoute
{
MailInfo Mail = 1;
string Key = 2;
}
message Game2C_MailState // ICustomRouteMessage,GameRoute
{
int32 MailState = 1;
int64 MailId = 2;
}
////////////// ******** 频道聊天 *******/////////////
/// 发送一个聊天消息给Chat服务器中间是经过Gate中转的