Merge pull request #2 from ahasasjeb/main

This commit is contained in:
Kei-Luna
2026-04-29 06:34:49 +09:00
7 changed files with 236 additions and 7 deletions

View File

@@ -20,6 +20,8 @@ public class InventoryData : BaseDatabaseDataHelper
[SugarColumn(IsJson = true)] [SugarColumn(IsJson = true)]
public Dictionary<uint, GameSupportCardInfo> SupportCards { get; set; } = []; // Key: UniqueId public Dictionary<uint, GameSupportCardInfo> SupportCards { get; set; } = []; // Key: UniqueId
public Dictionary<uint, uint> SkinTypesBySkinId { get; set; } = []; // Key: nSkinId, Value: client nType
} }
public class BaseGameItemInfo public class BaseGameItemInfo
@@ -88,7 +90,7 @@ public class GameSkinInfo : BaseGameItemInfo
Count = ItemCount, Count = ItemCount,
Flag = (uint)Flag, Flag = (uint)Flag,
}; };
proto.Slots[11] = SkinType; proto.Slots[11] = Math.Min(SkinType, 1);
return proto; return proto;
} }
} }

View File

@@ -124,6 +124,7 @@ public class CommandTextCHS
public HelpTextCHS Help { get; } = new(); public HelpTextCHS Help { get; } = new();
public GirlTextCHS Girl { get; } = new(); public GirlTextCHS Girl { get; } = new();
public GiveAllTextCHS GiveAll { get; } = new(); public GiveAllTextCHS GiveAll { get; } = new();
public DebugTextCHS Debug { get; } = new();
} }
#endregion #endregion
@@ -244,6 +245,21 @@ public class GiveAllTextCHS
public string GiveAllItems => "已向玩家添加 {0} 个 {1}"; public string GiveAllItems => "已向玩家添加 {0} 个 {1}";
} }
/// <summary>
/// path: Game.Command.Debug
/// </summary>
public class DebugTextCHS
{
public string Desc => "调试包输出开关";
public string Usage => "用法: /debug [on|off|simple|detail|file]";
public string Enabled => "已启用调试包输出。";
public string Disabled => "已禁用调试包输出。";
public string SimpleEnabled => "已启用简单调试包输出。";
public string DetailEnabled => "已启用详细调试包输出。";
public string FileEnabled => "个人调试文件输出已启用。";
public string FileDisabled => "个人调试文件输出已禁用。";
}
#endregion #endregion
#endregion #endregion

View File

@@ -124,6 +124,7 @@ public class CommandTextCHT
public HelpTextCHT Help { get; } = new(); public HelpTextCHT Help { get; } = new();
public GirlTextCHT Girl { get; } = new(); public GirlTextCHT Girl { get; } = new();
public GiveAllTextCHT GiveAll { get; } = new(); public GiveAllTextCHT GiveAll { get; } = new();
public DebugTextCHT Debug { get; } = new();
} }
#endregion #endregion
@@ -244,6 +245,21 @@ public class GiveAllTextCHT
public string GiveAllItems => "已向玩家添加 {0} 個 {1}"; public string GiveAllItems => "已向玩家添加 {0} 個 {1}";
} }
/// <summary>
/// path: Game.Command.Debug
/// </summary>
public class DebugTextCHT
{
public string Desc => "切換調試封包輸出";
public string Usage => "用法: /debug [on|off|simple|detail|file]";
public string Enabled => "已啟用調試封包輸出。";
public string Disabled => "已停用調試封包輸出。";
public string SimpleEnabled => "已啟用簡易調試封包輸出。";
public string DetailEnabled => "已啟用詳細調試封包輸出。";
public string FileEnabled => "個人調試檔案輸出已啟用。";
public string FileDisabled => "個人調試檔案輸出已停用。";
}
#endregion #endregion
#endregion #endregion

View File

@@ -83,6 +83,7 @@ public class CommandTextEN
public HelpTextEN Help { get; } = new(); public HelpTextEN Help { get; } = new();
public GirlTextEN Girl { get; } = new(); public GirlTextEN Girl { get; } = new();
public GiveAllTextEN GiveAll { get; } = new(); public GiveAllTextEN GiveAll { get; } = new();
public DebugTextEN Debug { get; } = new();
} }
#endregion #endregion
@@ -210,6 +211,21 @@ public class GiveAllTextEN
public string GiveAllItems => "Added {0} {1} to player!"; public string GiveAllItems => "Added {0} {1} to player!";
} }
/// <summary>
/// path: Game.Command.Debug
/// </summary>
public class DebugTextEN
{
public string Desc => "Toggle debug packet output";
public string Usage => "Usage: /debug [on|off|simple|detail|file]";
public string Enabled => "Debug packet output enabled.";
public string Disabled => "Debug packet output disabled.";
public string SimpleEnabled => "Simple debug packet output enabled.";
public string DetailEnabled => "Detailed debug packet output enabled.";
public string FileEnabled => "Personal debug file output enabled.";
public string FileDisabled => "Personal debug file output disabled.";
}
#endregion #endregion
#endregion #endregion

View File

@@ -0,0 +1,69 @@
using MikuSB.Configuration;
using MikuSB.Enums.Player;
using MikuSB.Util;
using MikuSB.Internationalization;
namespace MikuSB.GameServer.Command.Commands;
[CommandInfo("debug", "Game.Command.Debug.Desc", "Game.Command.Debug.Usage", ["dbg"], [PermEnum.Admin, PermEnum.Support])]
public class CommandDebug : ICommands
{
private static readonly Logger Logger = new("CommandManager");
[CommandDefault]
public async ValueTask ToggleDebug(CommandArg arg)
{
var option = arg.Args.FirstOrDefault()?.ToLowerInvariant() ?? "on";
var serverOption = ConfigManager.Config.ServerOption;
var message = option switch
{
"on" => EnableDebug(serverOption),
"off" => DisableDebug(serverOption),
"simple" => EnableSimpleDebug(serverOption),
"detail" => EnableDetailDebug(serverOption),
"file" => ToggleDebugFile(serverOption),
_ => I18NManager.Translate("Game.Command.Debug.Usage")
};
Logger.Info(message);
await arg.SendMsg(message);
}
private static string EnableDebug(ServerOption serverOption)
{
serverOption.EnableDebug = true;
serverOption.DebugMessage = true;
serverOption.DebugDetailMessage = true;
return I18NManager.Translate("Game.Command.Debug.Enabled");
}
private static string DisableDebug(ServerOption serverOption)
{
serverOption.EnableDebug = false;
return I18NManager.Translate("Game.Command.Debug.Disabled");
}
private static string EnableSimpleDebug(ServerOption serverOption)
{
serverOption.EnableDebug = true;
serverOption.DebugMessage = true;
serverOption.DebugDetailMessage = false;
return I18NManager.Translate("Game.Command.Debug.SimpleEnabled");
}
private static string EnableDetailDebug(ServerOption serverOption)
{
serverOption.EnableDebug = true;
serverOption.DebugMessage = true;
serverOption.DebugDetailMessage = true;
return I18NManager.Translate("Game.Command.Debug.DetailEnabled");
}
private static string ToggleDebugFile(ServerOption serverOption)
{
serverOption.SavePersonalDebugFile = !serverOption.SavePersonalDebugFile;
return serverOption.SavePersonalDebugFile
? I18NManager.Translate("Game.Command.Debug.FileEnabled")
: I18NManager.Translate("Game.Command.Debug.FileDisabled");
}
}

View File

@@ -1,4 +1,9 @@
using MikuSB.Proto; using MikuSB.Data;
using MikuSB.Database;
using MikuSB.Database.Inventory;
using MikuSB.Enums.Item;
using MikuSB.GameServer.Game.Player;
using MikuSB.Proto;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
@@ -11,9 +16,10 @@ public class GirlSkin_ChangeSkinType : ICallGSHandler
public async Task Handle(Connection connection, string param, ushort seqNo) public async Task Handle(Connection connection, string param, ushort seqNo)
{ {
var req = JsonSerializer.Deserialize<ChangeSkinTypeParam>(param); var req = JsonSerializer.Deserialize<ChangeSkinTypeParam>(param);
var skinType = ClampClientSkinType(req?.Type ?? 0);
var response = new JsonObject var response = new JsonObject
{ {
["nType"] = req?.Type ?? 1, ["nType"] = skinType,
["nSkinId"] = req?.SkinId ["nSkinId"] = req?.SkinId
}; };
if (req == null) if (req == null)
@@ -23,14 +29,20 @@ public class GirlSkin_ChangeSkinType : ICallGSHandler
} }
var player = connection.Player!; var player = connection.Player!;
var skinData = player.InventoryManager.GetSkinItem(req.SkinId); var skinData = GetOrCreateSkinItem(player, req.SkinId);
if (skinData != null)
skinData.SkinType = skinType;
player.InventoryManager.InventoryData.SkinTypesBySkinId ??= [];
player.InventoryManager.InventoryData.SkinTypesBySkinId[req.SkinId] = skinType;
DatabaseHelper.SaveDatabaseType(player.InventoryManager.InventoryData);
if (skinData == null) if (skinData == null)
{ {
await CallGSRouter.SendScript(connection, "GirlSkin_ChangeSkinType", response.ToJsonString()); await CallGSRouter.SendScript(connection, "GirlSkin_ChangeSkinType", response.ToJsonString());
return; return;
} }
skinData.SkinType = req.Type;
var sync = new NtfSyncPlayer var sync = new NtfSyncPlayer
{ {
Items = { skinData.ToProto() } Items = { skinData.ToProto() }
@@ -38,6 +50,42 @@ public class GirlSkin_ChangeSkinType : ICallGSHandler
await CallGSRouter.SendScript(connection, "GirlSkin_ChangeSkinType", response.ToJsonString(), sync); await CallGSRouter.SendScript(connection, "GirlSkin_ChangeSkinType", response.ToJsonString(), sync);
} }
internal static uint ClampClientSkinType(uint skinType)
{
return Math.Min(skinType, 1);
}
internal static GameSkinInfo? GetOrCreateSkinItem(PlayerInstance player, uint skinId)
{
var inventoryData = player.InventoryManager.InventoryData;
if (inventoryData.Skins.TryGetValue(skinId, out var skinInfo))
return skinInfo;
if (!GameData.CardSkinData.TryGetValue(skinId, out var skinData))
return null;
var templateId = GameResourceTemplateId.FromGdpl(skinData.Genre, skinData.Detail, skinData.Particular, skinData.Level);
skinInfo = player.InventoryManager.GetSkinItemByTemplateId(templateId);
if (skinInfo != null)
{
inventoryData.Skins.Remove(skinInfo.UniqueId);
skinInfo.UniqueId = skinId;
}
else
{
skinInfo = new GameSkinInfo
{
UniqueId = skinId,
TemplateId = templateId,
ItemType = ItemTypeEnum.TYPE_CARD_SKIN,
ItemCount = 1
};
}
inventoryData.Skins[skinId] = skinInfo;
return skinInfo;
}
} }
internal sealed class ChangeSkinTypeParam internal sealed class ChangeSkinTypeParam

View File

@@ -4,12 +4,14 @@ using MikuSB.Database.Account;
using MikuSB.Database.Player; using MikuSB.Database.Player;
using MikuSB.GameServer.Game.Player; using MikuSB.GameServer.Game.Player;
using MikuSB.GameServer.Server.CallGS; using MikuSB.GameServer.Server.CallGS;
using MikuSB.GameServer.Server.CallGS.Handlers.Girl;
using MikuSB.GameServer.Server.Packet.Send.Friend; using MikuSB.GameServer.Server.Packet.Send.Friend;
using MikuSB.GameServer.Server.Packet.Send.Login; using MikuSB.GameServer.Server.Packet.Send.Login;
using MikuSB.GameServer.Server.Packet.Send.Misc; using MikuSB.GameServer.Server.Packet.Send.Misc;
using MikuSB.Proto; using MikuSB.Proto;
using MikuSB.TcpSharp; using MikuSB.TcpSharp;
using MikuSB.Util; using MikuSB.Util;
using System.Text.Json.Nodes;
namespace MikuSB.GameServer.Server.Packet.Recv.Login; namespace MikuSB.GameServer.Server.Packet.Recv.Login;
@@ -54,6 +56,66 @@ public class HandlerReqLogin : Handler
await connection.Player.OnHeartBeat(); await connection.Player.OnHeartBeat();
await connection.SendPacket(new PacketNtfUpdateFriend(connection.Player!)); await connection.SendPacket(new PacketNtfUpdateFriend(connection.Player!));
ApplySavedGirlSkinTypes(connection.Player!);
await connection.SendPacket(new PacketNtfCallScript(connection.Player!.InventoryManager.InventoryData)); await connection.SendPacket(new PacketNtfCallScript(connection.Player!.InventoryManager.InventoryData));
await SendGirlSkinTypeOnLogin(connection);
}
private static void ApplySavedGirlSkinTypes(PlayerInstance player)
{
var inventoryData = player.InventoryManager.InventoryData;
inventoryData.SkinTypesBySkinId ??= [];
var changed = false;
foreach (var (skinId, skinType) in inventoryData.SkinTypesBySkinId.ToArray())
{
var clamped = GirlSkin_ChangeSkinType.ClampClientSkinType(skinType);
if (clamped != skinType)
{
inventoryData.SkinTypesBySkinId[skinId] = clamped;
changed = true;
}
var skinData = GirlSkin_ChangeSkinType.GetOrCreateSkinItem(player, skinId);
if (skinData != null && skinData.SkinType != clamped)
{
skinData.SkinType = clamped;
changed = true;
}
}
if (changed)
DatabaseHelper.SaveDatabaseType(inventoryData);
}
private static async Task SendGirlSkinTypeOnLogin(Connection connection)
{
var player = connection.Player;
if (player == null)
return;
var inventoryData = player.InventoryManager.InventoryData;
inventoryData.SkinTypesBySkinId ??= [];
foreach (var (skinId, skinType) in inventoryData.SkinTypesBySkinId)
{
var clamped = GirlSkin_ChangeSkinType.ClampClientSkinType(skinType);
var skinData = GirlSkin_ChangeSkinType.GetOrCreateSkinItem(player, skinId);
var response = new JsonObject
{
["nType"] = clamped,
["nSkinId"] = skinId
};
if (skinData == null)
{
await CallGSRouter.SendScript(connection, "GirlSkin_ChangeSkinType", response.ToJsonString());
continue;
}
await CallGSRouter.SendScript(connection, "GirlSkin_ChangeSkinType", response.ToJsonString(), new NtfSyncPlayer
{
Items = { skinData.ToProto() }
});
}
} }
} }