DB for starting tutorial

This commit is contained in:
rfi 2023-10-19 14:07:48 +07:00
parent 1ddd574645
commit 8d808170a5
10 changed files with 239 additions and 10 deletions

View File

@ -1,6 +1,9 @@
using System.Reflection; using System.Reflection;
using AscNet.Common.Database;
using MongoDB.Driver; using MongoDB.Driver;
using Config.Net; using Config.Net;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace AscNet.Common namespace AscNet.Common
@ -14,6 +17,7 @@ namespace AscNet.Common
static Common() static Common()
{ {
config = new ConfigurationBuilder<IConfig>().UseJsonFile("Configs/config.json").Build(); config = new ConfigurationBuilder<IConfig>().UseJsonFile("Configs/config.json").Build();
mongoClient = new( mongoClient = new(
new MongoClientSettings new MongoClientSettings
{ {

View File

@ -12,6 +12,8 @@ namespace AscNet.Common.Database
{ {
public static readonly IMongoCollection<Character> collection = Common.db.GetCollection<Character>("characters"); public static readonly IMongoCollection<Character> collection = Common.db.GetCollection<Character>("characters");
private uint NextEquipId => Equips.MaxBy(x => x.Id)?.Id + 1 ?? 1;
public static Character FromUid(long uid) public static Character FromUid(long uid)
{ {
return collection.AsQueryable().FirstOrDefault(x => x.Uid == uid) ?? Create(uid); return collection.AsQueryable().FirstOrDefault(x => x.Uid == uid) ?? Create(uid);
@ -22,7 +24,9 @@ namespace AscNet.Common.Database
Character character = new() Character character = new()
{ {
Uid = uid, Uid = uid,
Characters = new() Characters = new(),
Equips = new(),
Fashions = new()
}; };
// Lucia havers by default // Lucia havers by default
character.AddCharacter(1021001); character.AddCharacter(1021001);
@ -36,8 +40,12 @@ namespace AscNet.Common.Database
{ {
CharacterTable? character = CharacterTableReader.Instance.FromId((int)id); CharacterTable? character = CharacterTableReader.Instance.FromId((int)id);
CharacterSkillTable? characterSkill = CharacterSkillTableReader.Instance.FromCharacterId((int)id); CharacterSkillTable? characterSkill = CharacterSkillTableReader.Instance.FromCharacterId((int)id);
if (character is null || characterSkill is null) if (character is null || characterSkill is null)
throw new ArgumentException("Invlid character id!", nameof(id)); throw new ArgumentException("Invalid character id!", nameof(id));
if (Characters.FirstOrDefault(x => x.Id == character.Id) is not null)
throw new ArgumentException("Character already obtained!", nameof(id));
NotifyCharacterDataList.NotifyCharacterDataListCharacterData characterData = new() NotifyCharacterDataList.NotifyCharacterDataListCharacterData characterData = new()
{ {
Id = (uint)character.Id, Id = (uint)character.Id,
@ -64,10 +72,38 @@ namespace AscNet.Common.Database
Id = uint.Parse(x.ToString().Take(6).ToArray()), Id = uint.Parse(x.ToString().Take(6).ToArray()),
Level = 1 Level = 1
})); }));
Fashions.Add(new()
{
Id = character.DefaultNpcFashtionId,
IsLock = false
});
if (character.EquipId > 0)
AddEquip((uint)character.EquipId, character.Id);
Characters.Add(characterData); Characters.Add(characterData);
} }
public void AddEquip(uint equipId, int characterId = 0)
{
NotifyEquipDataList.NotifyEquipDataListEquipData equipData = new()
{
Id = NextEquipId,
TemplateId = equipId,
CharacterId = characterId,
Level = 1,
Exp = 0,
Breakthrough = 0,
ResonanceInfo = new(),
UnconfirmedResonanceInfo = new(),
AwakeSlotList = new(),
IsLock = false,
CreateTime = (uint)DateTimeOffset.Now.ToUnixTimeSeconds(),
IsRecycle = false
};
Equips.Add(equipData);
}
[BsonId] [BsonId]
public ObjectId Id { get; set; } public ObjectId Id { get; set; }
@ -75,8 +111,16 @@ namespace AscNet.Common.Database
[BsonRequired] [BsonRequired]
public long Uid { get; set; } public long Uid { get; set; }
[BsonElement("uid")] [BsonElement("characters")]
[BsonRequired] [BsonRequired]
public List<NotifyCharacterDataList.NotifyCharacterDataListCharacterData> Characters { get; set; } public List<NotifyCharacterDataList.NotifyCharacterDataListCharacterData> Characters { get; set; }
[BsonElement("equips")]
[BsonRequired]
public List<NotifyEquipDataList.NotifyEquipDataListEquipData> Equips { get; set; }
[BsonElement("fashions")]
[BsonRequired]
public List<FashionList> Fashions { get; set; }
} }
} }

View File

@ -0,0 +1,19 @@
using System.Linq.Expressions;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Options;
namespace AscNet.Common.Database
{
public static class DatabaseExtensions
{
public static BsonClassMap<T> SetDictionaryRepresentation<T, TMember>(this BsonClassMap<T> classMap, Expression<Func<T, TMember>> memberLambda, DictionaryRepresentation representation)
{
var memberMap = classMap.GetMemberMap(memberLambda);
var serializer = memberMap.GetSerializer();
if (serializer is IDictionaryRepresentationConfigurable dictionaryRepresentationSerializer)
serializer = dictionaryRepresentationSerializer.WithDictionaryRepresentation(representation);
memberMap.SetSerializer(serializer);
return classMap;
}
}
}

View File

@ -2,6 +2,8 @@
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Driver; using MongoDB.Driver;
using AscNet.Common.MsgPack; using AscNet.Common.MsgPack;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Options;
namespace AscNet.Common.Database namespace AscNet.Common.Database
{ {
@ -10,7 +12,7 @@ namespace AscNet.Common.Database
{ {
public static readonly IMongoCollection<Player> collection = Common.db.GetCollection<Player>("players"); public static readonly IMongoCollection<Player> collection = Common.db.GetCollection<Player>("players");
public static Player FromId(long id) public static Player FromPlayerId(long id)
{ {
return collection.AsQueryable().FirstOrDefault(x => x.PlayerData.Id == id) ?? Create(id); return collection.AsQueryable().FirstOrDefault(x => x.PlayerData.Id == id) ?? Create(id);
} }
@ -48,13 +50,45 @@ namespace AscNet.Common.Database
CreateTime = DateTimeOffset.Now.ToUnixTimeSeconds(), CreateTime = DateTimeOffset.Now.ToUnixTimeSeconds(),
LastLoginTime = DateTimeOffset.Now.ToUnixTimeSeconds(), LastLoginTime = DateTimeOffset.Now.ToUnixTimeSeconds(),
Flags = 1 Flags = 1
},
HeadPortraits = new(),
TeamGroups = new()
{
{1, new TeamGroupDatum()
{
TeamType = 1,
TeamId = 1,
CaptainPos = 1,
FirstFightPos = 1,
TeamData = new()
{
{1, 1021001},
{2, 0},
{3, 0}
},
TeamName = null
}}
} }
}; };
player.AddHead(9000001);
player.AddHead(9000002);
player.AddHead(9000003);
collection.InsertOne(player); collection.InsertOne(player);
return player; return player;
} }
public void AddHead(int id)
{
HeadPortraits.Add(new()
{
Id = id,
LeftCount = 1,
BeginTime = DateTimeOffset.Now.ToUnixTimeSeconds()
});
}
[BsonId] [BsonId]
public ObjectId Id { get; set; } public ObjectId Id { get; set; }
@ -65,5 +99,14 @@ namespace AscNet.Common.Database
[BsonElement("player_data")] [BsonElement("player_data")]
[BsonRequired] [BsonRequired]
public PlayerData PlayerData { get; set; } public PlayerData PlayerData { get; set; }
[BsonElement("head_portraits")]
[BsonRequired]
public List<HeadPortraitList> HeadPortraits { get; set; }
[BsonElement("team_groups")]
[BsonRequired]
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
public Dictionary<int, TeamGroupDatum> TeamGroups { get; set; }
} }
} }

View File

@ -0,0 +1,71 @@
using AscNet.Common.MsgPack;
using AscNet.Table.share.guide;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Options;
using MongoDB.Driver;
namespace AscNet.Common.Database
{
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public class Stage
{
public static readonly IMongoCollection<Stage> collection = Common.db.GetCollection<Stage>("stages");
public static Stage FromUid(long uid)
{
return collection.AsQueryable().FirstOrDefault(x => x.Uid == uid) ?? Create(uid);
}
private static Stage Create(long uid)
{
Stage stage = new()
{
Stages = new()
};
foreach (var guideFight in GuideFightTableReader.Instance.All)
{
stage.AddStage(new StageDatum()
{
StageId = guideFight.StageId,
StarsMark = 7,
Passed = true,
PassTimesToday = 0,
PassTimesTotal = 1,
BuyCount = 0,
Score = 0,
LastPassTime = DateTimeOffset.Now.ToUnixTimeSeconds(),
RefreshTime = DateTimeOffset.Now.ToUnixTimeSeconds(),
CreateTime = DateTimeOffset.Now.ToUnixTimeSeconds(),
BestRecordTime = guideFight.DefaultRecordTime,
LastRecordTime = guideFight.DefaultRecordTime,
BestCardIds = new List<long>() { 1021001 },
LastCardIds = new List<long>() { 1021001 }
});
}
collection.InsertOne(stage);
return stage;
}
public void AddStage(StageDatum stageData)
{
Stages.Add(stageData.StageId, stageData);
}
[BsonId]
public ObjectId Id { get; set; }
[BsonElement("uid")]
[BsonRequired]
public long Uid { get; set; }
[BsonElement("stages")]
[BsonRequired]
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
public Dictionary<long, StageDatum> Stages { get; set; }
}
}

View File

@ -1,5 +1,7 @@
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
using MessagePack; using MessagePack;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Options;
namespace AscNet.Common.MsgPack namespace AscNet.Common.MsgPack
{ {
@ -144,7 +146,7 @@ namespace AscNet.Common.MsgPack
[MessagePackObject(true)] [MessagePackObject(true)]
public partial class FubenData public partial class FubenData
{ {
public Dictionary<int, StageDatum> StageData { get; set; } public Dictionary<long, StageDatum> StageData { get; set; }
public FubenBaseData FubenBaseData { get; set; } public FubenBaseData FubenBaseData { get; set; }
public List<object> UnlockHideStages { get; set; } = new(); public List<object> UnlockHideStages { get; set; } = new();
public List<object> StageDifficulties { get; set; } = new(); public List<object> StageDifficulties { get; set; } = new();
@ -191,7 +193,7 @@ namespace AscNet.Common.MsgPack
public partial class FubenMainLineData public partial class FubenMainLineData
{ {
public List<long> TreasureData { get; set; } = new(); public List<long> TreasureData { get; set; } = new();
public Dictionary<int, long> LastPassStage { get; set; } public Dictionary<int, long> LastPassStage { get; set; } = new();
public List<dynamic> MainChapterEventInfos { get; set; } = new(); public List<dynamic> MainChapterEventInfos { get; set; } = new();
} }
@ -297,8 +299,9 @@ namespace AscNet.Common.MsgPack
public long TeamId { get; set; } public long TeamId { get; set; }
public long CaptainPos { get; set; } public long CaptainPos { get; set; }
public long FirstFightPos { get; set; } public long FirstFightPos { get; set; }
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
public Dictionary<int, long> TeamData { get; set; } public Dictionary<int, long> TeamData { get; set; }
public object TeamName { get; set; } public string? TeamName { get; set; }
} }
[MessagePackObject(true)] [MessagePackObject(true)]

View File

@ -39,6 +39,8 @@ namespace AscNet.GameServer.Handlers
} }
session.player = player; session.player = player;
session.character = Character.FromUid(player.PlayerData.Id);
session.stage = Stage.FromUid(player.PlayerData.Id);
session.SendResponse(new LoginResponse session.SendResponse(new LoginResponse
{ {
Code = 0, Code = 0,
@ -54,7 +56,18 @@ namespace AscNet.GameServer.Handlers
public static void ReconnectRequestHandler(Session session, Packet.Request packet) public static void ReconnectRequestHandler(Session session, Packet.Request packet)
{ {
ReconnectRequest request = MessagePackSerializer.Deserialize<ReconnectRequest>(packet.Content); ReconnectRequest request = MessagePackSerializer.Deserialize<ReconnectRequest>(packet.Content);
Player? player = Player.FromToken(request.Token); Player? player;
if (session.player is not null)
player = session.player;
else
{
player = Player.FromToken(request.Token);
if (player is not null && (session.character is null || session.stage is null))
{
session.character = Character.FromUid(player.PlayerData.Id);
session.stage = Stage.FromUid(player.PlayerData.Id);
}
}
if (player?.PlayerData.Id != request.PlayerId) if (player?.PlayerData.Id != request.PlayerId)
{ {
@ -82,8 +95,34 @@ namespace AscNet.GameServer.Handlers
// TODO: Move somewhere else, also split. // TODO: Move somewhere else, also split.
static void DoLogin(Session session) static void DoLogin(Session session)
{ {
NotifyLogin notifyLogin = JsonConvert.DeserializeObject<NotifyLogin>(File.ReadAllText("Data/NotifyLogin.json"))!; NotifyLogin notifyLogin = new()
{
PlayerData = session.player.PlayerData,
TeamGroupData = session.player.TeamGroups,
BaseEquipLoginData = new(),
FubenData = new()
{
StageData = session.stage.Stages,
FubenBaseData = new()
},
FubenMainLineData = new(),
FubenChapterExtraLoginData = new(),
FubenUrgentEventData = new(),
UseBackgroundId = 14000001 // main ui theme, table still failed to dump
};
notifyLogin.FashionList.AddRange(session.character.Fashions);
NotifyCharacterDataList notifyCharacterData = new();
notifyCharacterData.CharacterDataList.AddRange(session.character.Characters);
NotifyEquipDataList notifyEquipData = new();
notifyEquipData.EquipDataList.AddRange(session.character.Equips);
session.SendPush(notifyLogin); session.SendPush(notifyLogin);
session.SendPush(notifyCharacterData);
session.SendPush(notifyEquipData);
// NotifyLogin notifyLogin = JsonConvert.DeserializeObject<NotifyLogin>(File.ReadAllText("Data/NotifyLogin.json"))!;
// session.SendPush(notifyLogin);
// NEEDED to not softlock on stage selections! // NEEDED to not softlock on stage selections!
session.SendPush("NotifyFubenPrequelData", MessagePackSerializer.ConvertFromJson("{\"FubenPrequelData\": {\"RewardedStages\": [13010111, 13010112, 13010113, 13010211, 13010212, 13010213, 13010214, 13010215, 13010216, 13010311, 13010312, 13010313, 13010911, 13010912, 13010913, 13010414, 13010413, 13010415, 13010411, 13010412, 13010416, 13010316, 13010314, 13010315, 13010115, 13010116, 13010114, 13011011, 13011012, 13011013, 13011014, 13011015, 13011016], \"UnlockChallengeStages\": []}}")); session.SendPush("NotifyFubenPrequelData", MessagePackSerializer.ConvertFromJson("{\"FubenPrequelData\": {\"RewardedStages\": [13010111, 13010112, 13010113, 13010211, 13010212, 13010213, 13010214, 13010215, 13010216, 13010311, 13010312, 13010313, 13010911, 13010912, 13010913, 13010414, 13010413, 13010415, 13010411, 13010412, 13010416, 13010316, 13010314, 13010315, 13010115, 13010116, 13010114, 13011011, 13011012, 13011013, 13011014, 13011015, 13011016], \"UnlockChallengeStages\": []}}"));

View File

@ -15,6 +15,8 @@ namespace AscNet.GameServer
public readonly string id; public readonly string id;
public readonly TcpClient client; public readonly TcpClient client;
public Player player = default!; public Player player = default!;
public Character character = default!;
public Stage stage = default!;
public readonly Logger log; public readonly Logger log;
private long lastPacketTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); private long lastPacketTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
private ushort packetNo = 0; private ushort packetNo = 0;

View File

@ -121,7 +121,7 @@ namespace AscNet.SDKServer.Controllers
}); });
} }
Player player = Player.FromId(account.Uid); Player player = Player.FromPlayerId(account.Uid);
LoginGate gate = new() LoginGate gate = new()
{ {

View File

@ -54,6 +54,10 @@ namespace AscNet.SDKServer
{ {
await _next(context); await _next(context);
} }
catch (Exception ex)
{
log.Error($"{ex.Message} Request below:");
}
finally finally
{ {
log.Info($"{context.Response.StatusCode} {context.Request.Method.ToUpper()} {context.Request.Path + context.Request.QueryString}"); log.Info($"{context.Response.StatusCode} {context.Request.Method.ToUpper()} {context.Request.Path + context.Request.QueryString}");