2023-11-19 14:02:09 +00:00
|
|
|
|
using AscNet.Common.Database;
|
|
|
|
|
using AscNet.Common.MsgPack;
|
2023-11-26 14:08:59 +00:00
|
|
|
|
using AscNet.Common.Util;
|
|
|
|
|
using AscNet.Table.V2.share.item;
|
|
|
|
|
using AscNet.Table.V2.share.character;
|
2023-12-03 00:00:08 +00:00
|
|
|
|
using AscNet.Table.V2.share.character.grade;
|
2023-11-26 14:08:59 +00:00
|
|
|
|
using MessagePack;
|
|
|
|
|
using AscNet.Common;
|
2023-12-03 09:22:29 +00:00
|
|
|
|
using AscNet.Table.V2.share.character.quality;
|
2023-11-19 14:02:09 +00:00
|
|
|
|
|
|
|
|
|
namespace AscNet.GameServer.Handlers
|
|
|
|
|
{
|
2023-11-26 14:08:59 +00:00
|
|
|
|
#region MsgPackScheme
|
|
|
|
|
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
|
|
|
|
[MessagePackObject(true)]
|
|
|
|
|
public class CharacterLevelUpRequest
|
|
|
|
|
{
|
|
|
|
|
public uint TemplateId;
|
|
|
|
|
public Dictionary<int, int> UseItems;
|
|
|
|
|
}
|
2023-12-02 15:36:28 +00:00
|
|
|
|
|
2023-11-26 14:08:59 +00:00
|
|
|
|
[MessagePackObject(true)]
|
|
|
|
|
public class CharacterLevelUpResponse
|
|
|
|
|
{
|
|
|
|
|
public int Code;
|
|
|
|
|
}
|
2023-12-02 15:36:28 +00:00
|
|
|
|
|
2023-12-03 09:22:29 +00:00
|
|
|
|
[MessagePackObject(true)]
|
|
|
|
|
public class CharacterPromoteQualityRequest
|
|
|
|
|
{
|
|
|
|
|
public int TemplateId;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-03 09:34:02 +00:00
|
|
|
|
[MessagePackObject(true)]
|
|
|
|
|
public class CharacterPromoteQualityResponse
|
|
|
|
|
{
|
|
|
|
|
public int Code;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-02 15:36:28 +00:00
|
|
|
|
[MessagePackObject(true)]
|
|
|
|
|
public class CharacterActivateStarRequest
|
|
|
|
|
{
|
|
|
|
|
public int TemplateId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MessagePackObject(true)]
|
|
|
|
|
public class CharacterActivateStarResponse
|
|
|
|
|
{
|
|
|
|
|
public int Code;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MessagePackObject(true)]
|
|
|
|
|
public class CharacterPromoteGradeRequest
|
|
|
|
|
{
|
|
|
|
|
public int TemplateId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MessagePackObject(true)]
|
|
|
|
|
public class CharacterPromoteGradeResponse
|
|
|
|
|
{
|
|
|
|
|
public int Code;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-02 07:28:19 +00:00
|
|
|
|
[MessagePackObject(true)]
|
|
|
|
|
public class CharacterExchangeRequest
|
|
|
|
|
{
|
|
|
|
|
public int TemplateId;
|
|
|
|
|
}
|
2023-12-02 15:36:28 +00:00
|
|
|
|
|
2023-12-02 07:28:19 +00:00
|
|
|
|
[MessagePackObject(true)]
|
|
|
|
|
public class CharacterExchangeResponse
|
|
|
|
|
{
|
|
|
|
|
public int Code;
|
|
|
|
|
}
|
2023-12-02 15:36:28 +00:00
|
|
|
|
|
2023-12-02 07:28:19 +00:00
|
|
|
|
[MessagePackObject(true)]
|
|
|
|
|
public class FashionSyncNotify
|
|
|
|
|
{
|
|
|
|
|
public List<FashionList> FashionList = new();
|
|
|
|
|
}
|
2023-11-26 14:08:59 +00:00
|
|
|
|
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
|
|
|
|
#endregion
|
|
|
|
|
|
2023-11-19 14:02:09 +00:00
|
|
|
|
internal class CharacterModule
|
|
|
|
|
{
|
2023-12-02 15:36:28 +00:00
|
|
|
|
[RequestPacketHandler("CharacterLevelUpRequest")]
|
|
|
|
|
public static void CharacterLevelUpRequestHandler(Session session, Packet.Request packet)
|
2023-12-02 07:28:19 +00:00
|
|
|
|
{
|
2023-12-02 15:36:28 +00:00
|
|
|
|
CharacterLevelUpRequest request = packet.Deserialize<CharacterLevelUpRequest>();
|
2023-12-02 07:28:19 +00:00
|
|
|
|
CharacterTable? characterData = TableReaderV2.Parse<CharacterTable>().FirstOrDefault(x => x.Id == request.TemplateId);
|
|
|
|
|
|
2023-12-02 15:36:28 +00:00
|
|
|
|
if (characterData is null || !session.character.Characters.Any(x => x.Id == characterData.Id))
|
2023-12-02 07:28:19 +00:00
|
|
|
|
{
|
2023-12-02 15:36:28 +00:00
|
|
|
|
// CharacterManagerGetCharacterTemplateNotFound
|
|
|
|
|
session.SendResponse(new CharacterLevelUpResponse() { Code = 20009001 }, packet.Id);
|
2023-12-02 07:28:19 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-02 15:36:28 +00:00
|
|
|
|
NotifyItemDataList notifyItemData = new();
|
|
|
|
|
int totalExp = 0;
|
|
|
|
|
foreach (var item in request.UseItems)
|
2023-12-02 07:28:19 +00:00
|
|
|
|
{
|
2023-12-02 15:36:28 +00:00
|
|
|
|
ItemTable? itemTable = TableReaderV2.Parse<ItemTable>().FirstOrDefault(x => x.Id == item.Key);
|
|
|
|
|
if (itemTable is not null)
|
2023-12-02 07:28:19 +00:00
|
|
|
|
{
|
2023-12-02 15:36:28 +00:00
|
|
|
|
totalExp += itemTable.GetCharacterExp(characterData.Type) * item.Value;
|
|
|
|
|
notifyItemData.ItemDataList.Add(session.inventory.Do(item.Key, item.Value * -1));
|
|
|
|
|
}
|
2023-12-02 07:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
session.SendPush(notifyItemData);
|
|
|
|
|
|
2023-12-02 15:36:28 +00:00
|
|
|
|
var characterUp = session.character.AddCharacterExp(characterData.Id, totalExp, (int)session.player.PlayerData.Level);
|
|
|
|
|
if (characterUp is not null)
|
2023-12-02 07:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
NotifyCharacterDataList notifyCharacterData = new();
|
2023-12-02 15:36:28 +00:00
|
|
|
|
notifyCharacterData.CharacterDataList.Add(characterUp);
|
2023-12-02 07:28:19 +00:00
|
|
|
|
session.SendPush(notifyCharacterData);
|
|
|
|
|
}
|
2023-12-02 15:36:28 +00:00
|
|
|
|
|
|
|
|
|
session.SendResponse(new CharacterLevelUpResponse(), packet.Id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[RequestPacketHandler("CharacterPromoteGradeRequest")]
|
|
|
|
|
public static void CharacterPromoteGradeRequestHandler(Session session, Packet.Request packet)
|
|
|
|
|
{
|
|
|
|
|
CharacterPromoteGradeRequest req = packet.Deserialize<CharacterPromoteGradeRequest>();
|
|
|
|
|
var character = session.character.Characters.Find(c => c.Id == req.TemplateId);
|
2023-12-03 00:00:08 +00:00
|
|
|
|
var currentGrade = TableReaderV2.Parse<CharacterGradeTable>().Find(x => x.CharacterId == req.TemplateId && x.Grade == character?.Grade);
|
2023-12-02 15:36:28 +00:00
|
|
|
|
|
2023-12-03 00:00:08 +00:00
|
|
|
|
if (character is not null && currentGrade is not null)
|
2023-12-02 07:28:19 +00:00
|
|
|
|
{
|
2023-12-03 00:00:08 +00:00
|
|
|
|
var nextGrade = TableReaderV2.Parse<CharacterGradeTable>().Where(x => x.CharacterId == req.TemplateId && x.Grade > character.Grade).OrderBy(x => x.Grade).FirstOrDefault()?.Grade ?? character.Grade;
|
|
|
|
|
if (character.Grade == nextGrade)
|
|
|
|
|
{
|
|
|
|
|
// CharacterManagerMaxGrade
|
|
|
|
|
session.SendResponse(new CharacterPromoteGradeResponse() { Code = 20009019 }, packet.Id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (currentGrade.UseItemKey is not null)
|
|
|
|
|
{
|
|
|
|
|
NotifyItemDataList notifyItemData = new();
|
|
|
|
|
notifyItemData.ItemDataList.Add(session.inventory.Do(currentGrade.UseItemKey ?? 1, (currentGrade.UseItemCount ?? 0) * -1));
|
|
|
|
|
session.SendPush(notifyItemData);
|
|
|
|
|
}
|
2023-12-02 15:36:28 +00:00
|
|
|
|
|
2023-12-03 00:00:08 +00:00
|
|
|
|
character.Grade = nextGrade;
|
2023-12-02 15:36:28 +00:00
|
|
|
|
|
|
|
|
|
session.SendPush(new NotifyCharacterDataList()
|
|
|
|
|
{
|
|
|
|
|
CharacterDataList = { character }
|
|
|
|
|
});
|
2023-12-02 07:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-02 15:36:28 +00:00
|
|
|
|
session.SendResponse(new CharacterPromoteGradeResponse(), packet.Id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[RequestPacketHandler("CharacterActivateStarRequest")]
|
|
|
|
|
public static void CharacterActivateStarRequestHandler(Session session, Packet.Request packet)
|
|
|
|
|
{
|
|
|
|
|
CharacterActivateStarRequest req = packet.Deserialize<CharacterActivateStarRequest>();
|
|
|
|
|
var character = session.character.Characters.Find(c => c.Id == req.TemplateId);
|
2023-12-03 09:22:29 +00:00
|
|
|
|
var characterData = TableReaderV2.Parse<CharacterTable>().Find(x => x.Id == req.TemplateId);
|
|
|
|
|
var characterQualityFragment = TableReaderV2.Parse<CharacterQualityFragmentTable>().Find(x => x.Type == characterData?.Type && x.Quality == character?.Quality);
|
2023-12-02 15:36:28 +00:00
|
|
|
|
|
2023-12-03 09:22:29 +00:00
|
|
|
|
try
|
2023-12-02 15:36:28 +00:00
|
|
|
|
{
|
2023-12-03 09:22:29 +00:00
|
|
|
|
if (character is null)
|
|
|
|
|
{
|
|
|
|
|
// CharacterManagerGetCharacterByIdNotFound
|
|
|
|
|
throw new ServerCodeException("Character data not found!", 20009011);
|
|
|
|
|
}
|
|
|
|
|
if (characterData is null)
|
|
|
|
|
{
|
|
|
|
|
// CharacterManagerGetCharacterDataNotFound
|
|
|
|
|
throw new ServerCodeException("Character table data not found!", 20009021);
|
|
|
|
|
}
|
|
|
|
|
if (characterQualityFragment is null)
|
|
|
|
|
{
|
|
|
|
|
// CharacterManagerGetQualityFragmentTemplateNotFound
|
|
|
|
|
throw new ServerCodeException("Character quality fragment table data not found!", 20009004);
|
|
|
|
|
}
|
2023-12-02 15:36:28 +00:00
|
|
|
|
|
2023-12-03 09:22:29 +00:00
|
|
|
|
if (character.Star < characterQualityFragment.StarUseCount.Count)
|
|
|
|
|
{
|
|
|
|
|
if (characterQualityFragment.StarUseCount[character.Star] > 0)
|
|
|
|
|
{
|
|
|
|
|
NotifyItemDataList notifyItemData = new();
|
|
|
|
|
notifyItemData.ItemDataList.Add(session.inventory.Do(characterData.ItemId, characterQualityFragment.StarUseCount[character.Star] * -1));
|
|
|
|
|
session.SendPush(notifyItemData);
|
|
|
|
|
}
|
|
|
|
|
character.Star++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// CharacterManagerActivateStarMaxStar
|
2023-12-03 09:34:02 +00:00
|
|
|
|
throw new ServerCodeException("Character star already maxed!", 20009015);
|
2023-12-03 09:22:29 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (ServerCodeException ex)
|
|
|
|
|
{
|
|
|
|
|
session.SendResponse(new CharacterActivateStarResponse() { Code = ex.Code }, packet.Id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-12-02 15:36:28 +00:00
|
|
|
|
|
2023-12-03 09:22:29 +00:00
|
|
|
|
session.SendPush(new NotifyCharacterDataList()
|
|
|
|
|
{
|
|
|
|
|
CharacterDataList = { character }
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
session.SendResponse(new CharacterActivateStarResponse(), packet.Id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[RequestPacketHandler("CharacterPromoteQualityRequest")]
|
|
|
|
|
public static void CharacterPromoteQualityRequestHandler(Session session, Packet.Request packet)
|
|
|
|
|
{
|
|
|
|
|
CharacterPromoteQualityRequest req = packet.Deserialize<CharacterPromoteQualityRequest>();
|
|
|
|
|
var character = session.character.Characters.Find(c => c.Id == req.TemplateId);
|
|
|
|
|
var characterData = TableReaderV2.Parse<CharacterTable>().Find(x => x.Id == req.TemplateId);
|
|
|
|
|
var characterQualityFragment = TableReaderV2.Parse<CharacterQualityFragmentTable>().Find(x => x.Type == characterData?.Type && x.Quality == character?.Quality);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (character is null)
|
2023-12-02 15:36:28 +00:00
|
|
|
|
{
|
2023-12-03 09:22:29 +00:00
|
|
|
|
// CharacterManagerGetCharacterByIdNotFound
|
|
|
|
|
throw new ServerCodeException("Character data not found!", 20009011);
|
|
|
|
|
}
|
|
|
|
|
if (characterData is null)
|
|
|
|
|
{
|
|
|
|
|
// CharacterManagerGetCharacterDataNotFound
|
|
|
|
|
throw new ServerCodeException("Character table data not found!", 20009021);
|
|
|
|
|
}
|
|
|
|
|
if (characterQualityFragment is null)
|
|
|
|
|
{
|
|
|
|
|
// CharacterManagerGetQualityFragmentTemplateNotFound
|
|
|
|
|
throw new ServerCodeException("Character quality fragment table data not found!", 20009004);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TableReaderV2.Parse<CharacterQualityFragmentTable>().Any(x => x.Type == characterData?.Type && x.Quality == character?.Quality + 1))
|
|
|
|
|
{
|
|
|
|
|
if (characterQualityFragment.PromoteUseCoin is not null && characterQualityFragment.PromoteUseCoin > 0)
|
|
|
|
|
{
|
|
|
|
|
NotifyItemDataList notifyItemData = new();
|
|
|
|
|
notifyItemData.ItemDataList.Add(session.inventory.Do(characterQualityFragment.PromoteItemId ?? 1, (characterQualityFragment.PromoteUseCoin ?? 0) * -1));
|
|
|
|
|
session.SendPush(notifyItemData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
character.Star = 0;
|
|
|
|
|
character.Quality++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// CharacterManagerMaxQuality
|
|
|
|
|
throw new ServerCodeException("Character quality already maxed!", 20009016);
|
|
|
|
|
}
|
2023-12-02 15:36:28 +00:00
|
|
|
|
}
|
2023-12-03 09:22:29 +00:00
|
|
|
|
catch (ServerCodeException ex)
|
|
|
|
|
{
|
2023-12-03 09:34:02 +00:00
|
|
|
|
session.SendResponse(new CharacterPromoteQualityResponse() { Code = ex.Code }, packet.Id);
|
2023-12-03 09:22:29 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
session.SendPush(new NotifyCharacterDataList()
|
|
|
|
|
{
|
|
|
|
|
CharacterDataList = { character }
|
|
|
|
|
});
|
|
|
|
|
|
2023-12-03 09:34:02 +00:00
|
|
|
|
session.SendResponse(new CharacterPromoteQualityResponse(), packet.Id);
|
2023-12-02 07:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-11-19 14:02:09 +00:00
|
|
|
|
[RequestPacketHandler("CharacterUpgradeSkillGroupRequest")]
|
|
|
|
|
public static void CharacterUpgradeSkillGroupRequestHandler(Session session, Packet.Request packet)
|
|
|
|
|
{
|
|
|
|
|
CharacterUpgradeSkillGroupRequest request = packet.Deserialize<CharacterUpgradeSkillGroupRequest>();
|
|
|
|
|
|
|
|
|
|
var upgradeResult = session.character.UpgradeCharacterSkillGroup(request.SkillGroupId, request.Count);
|
|
|
|
|
|
|
|
|
|
NotifyCharacterDataList notifyCharacterData = new();
|
|
|
|
|
notifyCharacterData.CharacterDataList.AddRange(session.character.Characters.Where(x => upgradeResult.AffectedCharacters.Contains(x.Id)));
|
|
|
|
|
|
|
|
|
|
NotifyItemDataList notifyItemData = new();
|
2023-12-02 15:36:28 +00:00
|
|
|
|
notifyItemData.ItemDataList.AddRange(new Item[] {
|
|
|
|
|
session.inventory.Do(Inventory.Coin, upgradeResult.CoinCost * -1),
|
|
|
|
|
session.inventory.Do(Inventory.SkillPoint, upgradeResult.SkillPointCost * -1)
|
2023-11-20 15:19:46 +00:00
|
|
|
|
});
|
2023-11-19 14:02:09 +00:00
|
|
|
|
|
|
|
|
|
session.SendPush(notifyCharacterData);
|
|
|
|
|
session.SendPush(notifyItemData);
|
|
|
|
|
|
|
|
|
|
session.SendResponse(new CharacterUpgradeSkillGroupResponse(), packet.Id);
|
|
|
|
|
}
|
2023-11-26 14:08:59 +00:00
|
|
|
|
|
2023-12-02 15:36:28 +00:00
|
|
|
|
[RequestPacketHandler("CharacterExchangeRequest")]
|
|
|
|
|
public static void CharacterExchangeRequestHandler(Session session, Packet.Request packet)
|
2023-11-26 14:08:59 +00:00
|
|
|
|
{
|
2023-12-02 15:36:28 +00:00
|
|
|
|
CharacterExchangeRequest request = packet.Deserialize<CharacterExchangeRequest>();
|
2023-11-26 14:08:59 +00:00
|
|
|
|
CharacterTable? characterData = TableReaderV2.Parse<CharacterTable>().FirstOrDefault(x => x.Id == request.TemplateId);
|
|
|
|
|
|
2023-12-02 15:36:28 +00:00
|
|
|
|
if (characterData is null)
|
2023-11-26 14:08:59 +00:00
|
|
|
|
{
|
2023-12-02 15:36:28 +00:00
|
|
|
|
CharacterExchangeResponse rsp = new()
|
|
|
|
|
{
|
|
|
|
|
// CharacterManagerGetCharacterTemplateNotFound
|
|
|
|
|
Code = 20009001
|
|
|
|
|
};
|
|
|
|
|
session.SendResponse(rsp, packet.Id);
|
2023-11-26 14:08:59 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-02 15:36:28 +00:00
|
|
|
|
if (!session.inventory.Items.Any(x => x.Id == characterData.ItemId && x.Count >= 50))
|
2023-11-26 14:08:59 +00:00
|
|
|
|
{
|
2023-12-02 15:36:28 +00:00
|
|
|
|
CharacterExchangeResponse rsp = new()
|
2023-11-26 14:08:59 +00:00
|
|
|
|
{
|
2023-12-02 15:36:28 +00:00
|
|
|
|
// ItemCountNotEnough
|
|
|
|
|
Code = 20012004
|
|
|
|
|
};
|
|
|
|
|
session.SendResponse(rsp, packet.Id);
|
|
|
|
|
return;
|
2023-11-26 14:08:59 +00:00
|
|
|
|
}
|
2023-12-02 15:36:28 +00:00
|
|
|
|
|
|
|
|
|
NotifyItemDataList notifyItemData = new();
|
|
|
|
|
// idk if it's always 50, please investigate later...
|
|
|
|
|
notifyItemData.ItemDataList.Add(session.inventory.Do(characterData.ItemId, 50 * -1));
|
2023-11-26 14:08:59 +00:00
|
|
|
|
session.SendPush(notifyItemData);
|
|
|
|
|
|
2023-12-02 15:36:28 +00:00
|
|
|
|
try
|
2023-11-26 14:08:59 +00:00
|
|
|
|
{
|
2023-12-02 15:36:28 +00:00
|
|
|
|
NotifyEquipDataList notifyEquipData = new();
|
|
|
|
|
FashionSyncNotify fashionSync = new();
|
2023-11-26 14:08:59 +00:00
|
|
|
|
NotifyCharacterDataList notifyCharacterData = new();
|
2023-12-02 15:36:28 +00:00
|
|
|
|
var addRet = session.character.AddCharacter((uint)request.TemplateId);
|
|
|
|
|
|
|
|
|
|
notifyEquipData.EquipDataList.Add(addRet.Equip);
|
|
|
|
|
fashionSync.FashionList.Add(addRet.Fashion);
|
|
|
|
|
notifyCharacterData.CharacterDataList.Add(addRet.Character);
|
|
|
|
|
session.SendPush(notifyEquipData);
|
|
|
|
|
session.SendPush(fashionSync);
|
2023-11-26 14:08:59 +00:00
|
|
|
|
session.SendPush(notifyCharacterData);
|
|
|
|
|
}
|
2023-12-02 15:36:28 +00:00
|
|
|
|
catch (ServerCodeException ex)
|
|
|
|
|
{
|
|
|
|
|
CharacterExchangeResponse rsp = new() { Code = ex.Code };
|
|
|
|
|
session.SendResponse(rsp, packet.Id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-11-26 14:08:59 +00:00
|
|
|
|
|
2023-12-02 15:36:28 +00:00
|
|
|
|
session.SendResponse(new CharacterExchangeResponse(), packet.Id);
|
2023-11-26 14:08:59 +00:00
|
|
|
|
}
|
2023-11-19 14:02:09 +00:00
|
|
|
|
}
|
|
|
|
|
}
|