feat: skin system

This commit is contained in:
letheriver2007
2025-01-27 01:35:12 +08:00
committed by EggLink
parent 41cae9403e
commit 2b8b269a1d
12 changed files with 134 additions and 17 deletions

View File

@@ -234,7 +234,8 @@ public class CommandGiveall : ICommand
if (material.ItemMainType == ItemMainTypeEnum.Usable)
if (material.ItemSubType == ItemSubTypeEnum.HeadIcon ||
material.ItemSubType == ItemSubTypeEnum.PhoneTheme ||
material.ItemSubType == ItemSubTypeEnum.ChatBubble)
material.ItemSubType == ItemSubTypeEnum.ChatBubble ||
material.ItemSubType == ItemSubTypeEnum.AvatarSkin)
await player.InventoryManager!.AddItem(material.ID, 1, false);
await arg.SendMsg(I18NManager.Translate("Game.Command.GiveAll.GiveAllItems",

View File

@@ -0,0 +1,18 @@
namespace EggLink.DanhengServer.Data.Excel;
[ResourceEntity("AvatarSkin.json")]
public class AvatarSkinExcel : ExcelResource
{
public int ID { get; set; }
public int AvatarID { get; set; }
public override int GetId()
{
return ID;
}
public override void Loaded()
{
GameData.AvatarSkinData[ID] = this;
}
}

View File

@@ -42,6 +42,7 @@ public static class GameData
public static Dictionary<int, AvatarPromotionConfigExcel> AvatarPromotionConfigData { get; private set; } = [];
public static Dictionary<int, AvatarExpItemConfigExcel> AvatarExpItemConfigData { get; private set; } = [];
public static Dictionary<int, AvatarSkillTreeConfigExcel> AvatarSkillTreeConfigData { get; private set; } = [];
public static Dictionary<int, AvatarSkinExcel> AvatarSkinData { get; private set; } = [];
public static Dictionary<int, AvatarDemoConfigExcel> AvatarDemoConfigData { get; private set; } = [];
public static Dictionary<int, ExpTypeExcel> ExpTypeData { get; private set; } = [];

View File

@@ -10,4 +10,6 @@ public class PlayerUnlockData : BaseDatabaseDataHelper
[SugarColumn(IsJson = true)] public List<int> ChatBubbles { get; set; } = [];
[SugarColumn(IsJson = true)] public List<int> PhoneThemes { get; set; } = [];
[SugarColumn(IsJson = true)] public Dictionary<int, List<int>> Skins { get; set; } = [];
}

View File

@@ -6,6 +6,7 @@ using EggLink.DanhengServer.Enums.Item;
using EggLink.DanhengServer.Enums.Mission;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Avatar;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Lineup;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Player;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.PlayerSync;
@@ -77,6 +78,16 @@ public class InventoryManager(PlayerInstance player) : BasePlayerManager(player)
case ItemSubTypeEnum.PhoneTheme:
Player.PlayerUnlockData!.PhoneThemes.Add(itemId);
break;
case ItemSubTypeEnum.AvatarSkin:
var avatarId = GameData.AvatarSkinData[itemId].AvatarID;
if (!Player.PlayerUnlockData!.Skins.TryGetValue(avatarId, out var value))
{
value = [];
Player.PlayerUnlockData.Skins[avatarId] = value;
}
value.Add(itemId);
await Player.SendPacket(new PacketUnlockAvatarSkinScNotify(itemId));
break;
case ItemSubTypeEnum.Food:
case ItemSubTypeEnum.Book:
case ItemSubTypeEnum.FindChest:

View File

@@ -305,6 +305,17 @@ public class PlayerInstance(PlayerData data)
await SendPacket(new PacketPlayerSyncScNotify(avatar));
}
public async ValueTask ChangeAvatarSkin(int avatarId, int skinId)
{
PlayerUnlockData!.Skins.TryGetValue(avatarId, out var skins);
if (skins != null && (skins.Contains(skinId) || skinId == 0))
{
var avatar = AvatarManager!.GetAvatar(avatarId)!;
avatar.GetPathInfo(avatarId)!.Skin = skinId;
await SendPacket(new PacketPlayerSyncScNotify(avatar));
}
}
public async ValueTask<AvatarInfo> MarkAvatar(int avatarId, bool isMarked, bool sendPacket = true)
{
var avatar = AvatarManager!.GetAvatar(avatarId)!;

View File

@@ -0,0 +1,15 @@
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Avatar;
[Opcode(CmdIds.DressAvatarSkinCsReq)]
public class HandlerDressAvatarSkinCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var req = DressAvatarSkinCsReq.Parser.ParseFrom(data);
await connection.Player!.ChangeAvatarSkin((int)req.AvatarId, (int)req.SkinId);
await connection.SendPacket(CmdIds.DressAvatarSkinScRsp);
}
}

View File

@@ -0,0 +1,23 @@
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Avatar;
[Opcode(CmdIds.SetMultipleAvatarPathsCsReq)]
public class HandlerSetMultipleAvatarPathsCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var req = SetMultipleAvatarPathsCsReq.Parser.ParseFrom(data);
foreach (var targetAvatarType in req.AvatarIdList)
{
var avatarId = (int)targetAvatarType;
var baseAvatarId = connection.Player!.AvatarManager!.GetAvatar(avatarId)!.BaseAvatarId;
if (avatarId % 2 == 0) avatarId--;
await connection.Player!.ChangeAvatarPathType(baseAvatarId, (MultiPathAvatarType)avatarId);
}
await connection.SendPacket(CmdIds.SetMultipleAvatarPathsScRsp);
}
}

View File

@@ -0,0 +1,15 @@
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Avatar;
[Opcode(CmdIds.TakeOffAvatarSkinCsReq)]
public class HandlerTakeOffAvatarSkinCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var req = TakeOffAvatarSkinCsReq.Parser.ParseFrom(data);
await connection.Player!.ChangeAvatarSkin((int)req.AvatarId, 0);
await connection.SendPacket(CmdIds.TakeOffAvatarSkinScRsp);
}
}

View File

@@ -14,6 +14,9 @@ public class PacketGetAvatarDataScRsp : BasePacket
IsGetAll = true
};
player.PlayerUnlockData!.Skins.Values.ToList().ForEach(skin =>
proto.SkinList.AddRange(skin.Select(x => (uint)x)));
player.AvatarManager?.AvatarData?.Avatars?.ForEach(avatar =>
{
GameData.MultiplePathAvatarConfigData.TryGetValue(avatar.BaseAvatarId, out var multiPathAvatar);

View File

@@ -0,0 +1,17 @@
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Avatar;
public class PacketUnlockAvatarSkinScNotify : BasePacket
{
public PacketUnlockAvatarSkinScNotify(int skinId) : base(CmdIds.UnlockAvatarSkinScNotify)
{
var proto = new UnlockAvatarSkinScNotify
{
SkinId = (uint)skinId
};
SetData(proto);
}
}

View File

@@ -33,7 +33,7 @@ namespace EggLink.DanhengServer.Proto {
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::EggLink.DanhengServer.Proto.BCMLJCFOEFMReflection.Descriptor, global::EggLink.DanhengServer.Proto.AvatarReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::EggLink.DanhengServer.Proto.GetAvatarDataScRsp), global::EggLink.DanhengServer.Proto.GetAvatarDataScRsp.Parser, new[]{ "IsGetAll", "Retcode", "ANKHENIIACH", "JPNLPOPMKEJ", "AvatarList", "PNKCFEALAMI" }, null, null, null, null)
new pbr::GeneratedClrTypeInfo(typeof(global::EggLink.DanhengServer.Proto.GetAvatarDataScRsp), global::EggLink.DanhengServer.Proto.GetAvatarDataScRsp.Parser, new[]{ "IsGetAll", "Retcode", "SkinList", "JPNLPOPMKEJ", "AvatarList", "PNKCFEALAMI" }, null, null, null, null)
}));
}
#endregion
@@ -77,7 +77,7 @@ namespace EggLink.DanhengServer.Proto {
public GetAvatarDataScRsp(GetAvatarDataScRsp other) : this() {
isGetAll_ = other.isGetAll_;
retcode_ = other.retcode_;
aNKHENIIACH_ = other.aNKHENIIACH_.Clone();
skinList_ = other.skinList_.Clone();
jPNLPOPMKEJ_ = other.jPNLPOPMKEJ_;
avatarList_ = other.avatarList_.Clone();
pNKCFEALAMI_ = other.pNKCFEALAMI_.Clone();
@@ -114,15 +114,15 @@ namespace EggLink.DanhengServer.Proto {
}
}
/// <summary>Field number for the "ANKHENIIACH" field.</summary>
public const int ANKHENIIACHFieldNumber = 9;
private static readonly pb::FieldCodec<uint> _repeated_aNKHENIIACH_codec
/// <summary>Field number for the "skin_list" field.</summary>
public const int SkinListFieldNumber = 9;
private static readonly pb::FieldCodec<uint> _repeated_skinList_codec
= pb::FieldCodec.ForUInt32(74);
private readonly pbc::RepeatedField<uint> aNKHENIIACH_ = new pbc::RepeatedField<uint>();
private readonly pbc::RepeatedField<uint> skinList_ = new pbc::RepeatedField<uint>();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public pbc::RepeatedField<uint> ANKHENIIACH {
get { return aNKHENIIACH_; }
public pbc::RepeatedField<uint> SkinList {
get { return skinList_; }
}
/// <summary>Field number for the "JPNLPOPMKEJ" field.</summary>
@@ -176,7 +176,7 @@ namespace EggLink.DanhengServer.Proto {
}
if (IsGetAll != other.IsGetAll) return false;
if (Retcode != other.Retcode) return false;
if(!aNKHENIIACH_.Equals(other.aNKHENIIACH_)) return false;
if(!skinList_.Equals(other.skinList_)) return false;
if (JPNLPOPMKEJ != other.JPNLPOPMKEJ) return false;
if(!avatarList_.Equals(other.avatarList_)) return false;
if(!pNKCFEALAMI_.Equals(other.pNKCFEALAMI_)) return false;
@@ -189,7 +189,7 @@ namespace EggLink.DanhengServer.Proto {
int hash = 1;
if (IsGetAll != false) hash ^= IsGetAll.GetHashCode();
if (Retcode != 0) hash ^= Retcode.GetHashCode();
hash ^= aNKHENIIACH_.GetHashCode();
hash ^= skinList_.GetHashCode();
if (JPNLPOPMKEJ != 0) hash ^= JPNLPOPMKEJ.GetHashCode();
hash ^= avatarList_.GetHashCode();
hash ^= pNKCFEALAMI_.GetHashCode();
@@ -220,7 +220,7 @@ namespace EggLink.DanhengServer.Proto {
output.WriteRawTag(64);
output.WriteUInt32(JPNLPOPMKEJ);
}
aNKHENIIACH_.WriteTo(output, _repeated_aNKHENIIACH_codec);
skinList_.WriteTo(output, _repeated_skinList_codec);
pNKCFEALAMI_.WriteTo(output, _repeated_pNKCFEALAMI_codec);
if (IsGetAll != false) {
output.WriteRawTag(104);
@@ -245,7 +245,7 @@ namespace EggLink.DanhengServer.Proto {
output.WriteRawTag(64);
output.WriteUInt32(JPNLPOPMKEJ);
}
aNKHENIIACH_.WriteTo(ref output, _repeated_aNKHENIIACH_codec);
skinList_.WriteTo(ref output, _repeated_skinList_codec);
pNKCFEALAMI_.WriteTo(ref output, _repeated_pNKCFEALAMI_codec);
if (IsGetAll != false) {
output.WriteRawTag(104);
@@ -267,7 +267,7 @@ namespace EggLink.DanhengServer.Proto {
if (Retcode != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Retcode);
}
size += aNKHENIIACH_.CalculateSize(_repeated_aNKHENIIACH_codec);
size += skinList_.CalculateSize(_repeated_skinList_codec);
if (JPNLPOPMKEJ != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(JPNLPOPMKEJ);
}
@@ -291,7 +291,7 @@ namespace EggLink.DanhengServer.Proto {
if (other.Retcode != 0) {
Retcode = other.Retcode;
}
aNKHENIIACH_.Add(other.aNKHENIIACH_);
skinList_.Add(other.skinList_);
if (other.JPNLPOPMKEJ != 0) {
JPNLPOPMKEJ = other.JPNLPOPMKEJ;
}
@@ -326,7 +326,7 @@ namespace EggLink.DanhengServer.Proto {
}
case 74:
case 72: {
aNKHENIIACH_.AddEntriesFrom(input, _repeated_aNKHENIIACH_codec);
skinList_.AddEntriesFrom(input, _repeated_skinList_codec);
break;
}
case 90:
@@ -367,7 +367,7 @@ namespace EggLink.DanhengServer.Proto {
}
case 74:
case 72: {
aNKHENIIACH_.AddEntriesFrom(ref input, _repeated_aNKHENIIACH_codec);
skinList_.AddEntriesFrom(ref input, _repeated_skinList_codec);
break;
}
case 90: