mirror of
https://github.com/MikuLeaks/MikuSB.git
synced 2026-06-04 09:23:57 +00:00
Merge pull request #2 from ahasasjeb/main
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
69
GameServer/Command/Commands/CommandDebug.cs
Normal file
69
GameServer/Command/Commands/CommandDebug.cs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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() }
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user