diff --git a/Command/Command.csproj b/Command/Command.csproj
new file mode 100644
index 00000000..50071390
--- /dev/null
+++ b/Command/Command.csproj
@@ -0,0 +1,16 @@
+
+
+
+ net8.0
+ enable
+ enable
+ EggLink.DanhengServer.Command
+ DanhengCommand
+
+
+
+
+
+
+
+
diff --git a/GameServer/Command/Cmd/CommandAvatar.cs b/Command/Command/Cmd/CommandAvatar.cs
similarity index 93%
rename from GameServer/Command/Cmd/CommandAvatar.cs
rename to Command/Command/Cmd/CommandAvatar.cs
index 3338c135..408d41d8 100644
--- a/GameServer/Command/Cmd/CommandAvatar.cs
+++ b/Command/Command/Cmd/CommandAvatar.cs
@@ -80,7 +80,7 @@ namespace EggLink.DanhengServer.Command.Cmd
// sync
player.SendPacket(new PacketPlayerSyncScNotify(avatar));
- arg.SendMsg(I18nManager.Translate("Game.Command.Avatar.AvatarLevelSet", avatar.Excel?.Name ?? avatarId.ToString(), I18nManager.Translate("Word.Talent"), level.ToString()));
+ arg.SendMsg(I18nManager.Translate("Game.Command.Avatar.AvatarLevelSet", avatar.Excel?.Name?.Replace("{NICKNAME}", player.Data.Name) ?? avatarId.ToString(), I18nManager.Translate("Word.Talent"), level.ToString()));
}
[CommandMethod("get")]
@@ -153,7 +153,7 @@ namespace EggLink.DanhengServer.Command.Cmd
// sync
arg.Target.SendPacket(new PacketPlayerSyncScNotify(avatar));
- arg.SendMsg(I18nManager.Translate("Game.Command.Avatar.AvatarLevelSet", avatar.Excel?.Name ?? id.ToString(), I18nManager.Translate("Word.Rank"), rank.ToString()));
+ arg.SendMsg(I18nManager.Translate("Game.Command.Avatar.AvatarLevelSet", avatar.Excel?.Name?.Replace("{NICKNAME}", arg.Target.Player!.Data.Name) ?? id.ToString(), I18nManager.Translate("Word.Rank"), rank.ToString()));
}
}
@@ -206,7 +206,7 @@ namespace EggLink.DanhengServer.Command.Cmd
// sync
arg.Target.SendPacket(new PacketPlayerSyncScNotify(avatar));
- arg.SendMsg(I18nManager.Translate("Game.Command.Avatar.AvatarLevelSet", avatar.Excel?.Name ?? id.ToString(), I18nManager.Translate("Word.Avatar"), level.ToString()));
+ arg.SendMsg(I18nManager.Translate("Game.Command.Avatar.AvatarLevelSet", avatar.Excel?.Name?.Replace("{NICKNAME}", arg.Target.Player!.Data.Name) ?? id.ToString(), I18nManager.Translate("Word.Avatar"), level.ToString()));
}
}
}
diff --git a/GameServer/Command/Cmd/CommandGive.cs b/Command/Command/Cmd/CommandGive.cs
similarity index 100%
rename from GameServer/Command/Cmd/CommandGive.cs
rename to Command/Command/Cmd/CommandGive.cs
diff --git a/GameServer/Command/Cmd/CommandGiveall.cs b/Command/Command/Cmd/CommandGiveall.cs
similarity index 100%
rename from GameServer/Command/Cmd/CommandGiveall.cs
rename to Command/Command/Cmd/CommandGiveall.cs
diff --git a/GameServer/Command/Cmd/CommandHelp.cs b/Command/Command/Cmd/CommandHelp.cs
similarity index 83%
rename from GameServer/Command/Cmd/CommandHelp.cs
rename to Command/Command/Cmd/CommandHelp.cs
index 44ae4984..7fe24971 100644
--- a/GameServer/Command/Cmd/CommandHelp.cs
+++ b/Command/Command/Cmd/CommandHelp.cs
@@ -1,5 +1,4 @@
using EggLink.DanhengServer.Internationalization;
-using EggLink.DanhengServer.Program;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -14,8 +13,12 @@ namespace EggLink.DanhengServer.Command.Cmd
[CommandDefault]
public void Help(CommandArg arg)
{
- var commands = EntryPoint.CommandManager.CommandInfo.Values;
+ var commands = CommandManager.Instance?.CommandInfo.Values;
arg.SendMsg(I18nManager.Translate("Game.Command.Help.Commands"));
+ if (commands == null)
+ {
+ return;
+ }
foreach (var command in commands)
{
arg.SendMsg($"/{command.Name} - {I18nManager.Translate(command.Description)}\n{I18nManager.Translate("Game.Command.Help.CommandUsage")} {I18nManager.Translate(command.Usage)}");
diff --git a/GameServer/Command/Cmd/CommandHero.cs b/Command/Command/Cmd/CommandHero.cs
similarity index 100%
rename from GameServer/Command/Cmd/CommandHero.cs
rename to Command/Command/Cmd/CommandHero.cs
diff --git a/GameServer/Command/Cmd/CommandKick.cs b/Command/Command/Cmd/CommandKick.cs
similarity index 100%
rename from GameServer/Command/Cmd/CommandKick.cs
rename to Command/Command/Cmd/CommandKick.cs
diff --git a/GameServer/Command/Cmd/CommandLineup.cs b/Command/Command/Cmd/CommandLineup.cs
similarity index 100%
rename from GameServer/Command/Cmd/CommandLineup.cs
rename to Command/Command/Cmd/CommandLineup.cs
diff --git a/Command/Command/Cmd/CommandMail.cs b/Command/Command/Cmd/CommandMail.cs
new file mode 100644
index 00000000..4564e551
--- /dev/null
+++ b/Command/Command/Cmd/CommandMail.cs
@@ -0,0 +1,39 @@
+using EggLink.DanhengServer.Internationalization;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Command.Command.Cmd
+{
+ [CommandInfo("mail", "Game.Command.Mail.Desc", "Game.Command.Mail.Usage", permission: "")]
+ public class CommandMail : ICommand
+ {
+ [CommandDefault]
+ public void Mail(CommandArg arg)
+ {
+ if (arg.Target == null)
+ {
+ arg.SendMsg(I18nManager.Translate("Game.Command.Notice.PlayerNotFound"));
+ return;
+ }
+
+ if (arg.Args.Count < 5)
+ {
+ arg.SendMsg(I18nManager.Translate("Game.Command.Notice.InvalidArguments"));
+ return;
+ }
+
+ var sender = arg.Args[0];
+ var title = arg.Args[1];
+ var content = arg.Args[2];
+ var templateId = int.Parse(arg.Args[3]);
+ var expiredDay = int.Parse(arg.Args[4]);
+
+ arg.Target.Player!.MailManager!.SendMail(sender, title, content, templateId, expiredDay);
+
+ arg.SendMsg(I18nManager.Translate("Game.Command.Mail.MailSent"));
+ }
+ }
+}
diff --git a/GameServer/Command/Cmd/CommandMission.cs b/Command/Command/Cmd/CommandMission.cs
similarity index 100%
rename from GameServer/Command/Cmd/CommandMission.cs
rename to Command/Command/Cmd/CommandMission.cs
diff --git a/GameServer/Command/Cmd/CommandRelic.cs b/Command/Command/Cmd/CommandRelic.cs
similarity index 94%
rename from GameServer/Command/Cmd/CommandRelic.cs
rename to Command/Command/Cmd/CommandRelic.cs
index 7d34ce77..2caa124b 100644
--- a/GameServer/Command/Cmd/CommandRelic.cs
+++ b/Command/Command/Cmd/CommandRelic.cs
@@ -40,7 +40,8 @@ namespace EggLink.DanhengServer.Command.Cmd
}
GameData.RelicConfigData.TryGetValue(int.Parse(arg.BasicArgs[0]), out var itemConfig);
- if (itemConfig == null)
+ GameData.ItemConfigData.TryGetValue(int.Parse(arg.BasicArgs[0]), out var itemConfigExcel);
+ if (itemConfig == null || itemConfigExcel == null)
{
arg.SendMsg(I18nManager.Translate("Game.Command.Relic.RelicNotFound"));
return;
@@ -141,7 +142,7 @@ namespace EggLink.DanhengServer.Command.Cmd
player.InventoryManager!.AddItem(itemData);
}
- arg.SendMsg(I18nManager.Translate("Game.Command.Relic.RelicGiven", player.Uid.ToString(), amount.ToString(), itemData.ItemId.ToString(), itemData.MainAffix.ToString()));
+ arg.SendMsg(I18nManager.Translate("Game.Command.Relic.RelicGiven", player.Uid.ToString(), amount.ToString(), itemConfigExcel.Name ?? itemData.ItemId.ToString(), itemData.MainAffix.ToString()));
}
}
}
diff --git a/GameServer/Command/Cmd/CommandReload.cs b/Command/Command/Cmd/CommandReload.cs
similarity index 100%
rename from GameServer/Command/Cmd/CommandReload.cs
rename to Command/Command/Cmd/CommandReload.cs
diff --git a/GameServer/Command/Cmd/CommandRogue.cs b/Command/Command/Cmd/CommandRogue.cs
similarity index 100%
rename from GameServer/Command/Cmd/CommandRogue.cs
rename to Command/Command/Cmd/CommandRogue.cs
diff --git a/GameServer/Command/Cmd/CommandScene.cs b/Command/Command/Cmd/CommandScene.cs
similarity index 100%
rename from GameServer/Command/Cmd/CommandScene.cs
rename to Command/Command/Cmd/CommandScene.cs
diff --git a/GameServer/Command/Cmd/CommandUnlockAll.cs b/Command/Command/Cmd/CommandUnlockAll.cs
similarity index 100%
rename from GameServer/Command/Cmd/CommandUnlockAll.cs
rename to Command/Command/Cmd/CommandUnlockAll.cs
diff --git a/GameServer/Command/CommandArg.cs b/Command/Command/CommandArg.cs
similarity index 93%
rename from GameServer/Command/CommandArg.cs
rename to Command/Command/CommandArg.cs
index aefaac85..88c984c3 100644
--- a/GameServer/Command/CommandArg.cs
+++ b/Command/Command/CommandArg.cs
@@ -11,6 +11,7 @@ namespace EggLink.DanhengServer.Command
public class CommandArg
{
public string Raw { get; }
+ public List Args { get; } = [];
public List BasicArgs { get; } = [];
public Dictionary CharacterArgs { get; } = [];
public Connection? Target { get; set; }
@@ -33,14 +34,17 @@ namespace EggLink.DanhengServer.Command
try
{
CharacterArgs.Add(arg[..1], arg[1..]);
+ Args.Add(arg);
} catch
{
BasicArgs.Add(arg);
+ Args.Add(arg);
}
}
else
{
BasicArgs.Add(arg);
+ Args.Add(arg);
}
}
if (con != null)
diff --git a/GameServer/Command/CommandManager.cs b/Command/Command/CommandManager.cs
similarity index 93%
rename from GameServer/Command/CommandManager.cs
rename to Command/Command/CommandManager.cs
index c738dffe..ba2b5ab3 100644
--- a/GameServer/Command/CommandManager.cs
+++ b/Command/Command/CommandManager.cs
@@ -1,6 +1,6 @@
using EggLink.DanhengServer.Database;
+using EggLink.DanhengServer.GameServer.Command;
using EggLink.DanhengServer.Internationalization;
-using EggLink.DanhengServer.Program;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Server;
using EggLink.DanhengServer.Util;
@@ -16,6 +16,7 @@ namespace EggLink.DanhengServer.Command
{
public class CommandManager
{
+ public static CommandManager? Instance { get; private set; }
public Dictionary Commands { get; } = [];
public Dictionary CommandInfo { get; } = [];
public Logger Logger { get; } = new Logger("CommandManager");
@@ -23,6 +24,7 @@ namespace EggLink.DanhengServer.Command
public void RegisterCommand()
{
+ Instance = this;
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
{
var attr = type.GetCustomAttribute();
@@ -84,10 +86,15 @@ namespace EggLink.DanhengServer.Command
}
return;
}
- } else if (sender is PlayerCommandSender player)
+ } else
{
// player
- tempTarget = player.Player.Connection;
+ tempTarget = Listener.GetActiveConnection(sender.GetSender());
+ if (tempTarget == null)
+ {
+ sender.SendMsg(I18nManager.Translate("Game.Command.Notice.TargetNotFound", sender.GetSender().ToString()));
+ return;
+ }
}
if (tempTarget != null && !tempTarget.IsOnline)
diff --git a/GameServer/Command/CommandInfo.cs b/Common/Command/CommandInfo.cs
similarity index 100%
rename from GameServer/Command/CommandInfo.cs
rename to Common/Command/CommandInfo.cs
diff --git a/Common/Command/CommandSender.cs b/Common/Command/CommandSender.cs
new file mode 100644
index 00000000..38631aad
--- /dev/null
+++ b/Common/Command/CommandSender.cs
@@ -0,0 +1,37 @@
+using EggLink.DanhengServer.Database;
+using EggLink.DanhengServer.Database.Account;
+using EggLink.DanhengServer.Util;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Command
+{
+ public interface ICommandSender
+ {
+ public void SendMsg(string msg);
+
+ public bool HasPermission(string permission);
+
+ public int GetSender();
+ }
+
+ public class ConsoleCommandSender(Logger logger) : ICommandSender
+ {
+ public void SendMsg(string msg)
+ {
+ logger.Info(msg);
+ }
+
+ public bool HasPermission(string permission)
+ {
+ return true;
+ }
+ public int GetSender()
+ {
+ return 0;
+ }
+ }
+}
diff --git a/GameServer/Command/ICommand.cs b/Common/Command/ICommand.cs
similarity index 100%
rename from GameServer/Command/ICommand.cs
rename to Common/Command/ICommand.cs
diff --git a/Common/Common.csproj b/Common/Common.csproj
index 377b9ef3..4766b2b4 100644
--- a/Common/Common.csproj
+++ b/Common/Common.csproj
@@ -5,6 +5,7 @@
enable
enable
EggLink.DanhengServer
+ DanhengCommon
diff --git a/Common/Configuration/ConfigContainer.cs b/Common/Configuration/ConfigContainer.cs
index 3c12005e..1d42af7d 100644
--- a/Common/Configuration/ConfigContainer.cs
+++ b/Common/Configuration/ConfigContainer.cs
@@ -11,6 +11,7 @@ namespace EggLink.DanhengServer.Configuration
public DatabaseConfig Database { get; set; } = new DatabaseConfig();
public ServerOption ServerOption { get; set; } = new ServerOption();
public DownloadUrlConfig DownloadUrl { get; set; } = new DownloadUrlConfig();
+ public MuipServerConfig MuipServer { get; set; } = new MuipServerConfig();
}
public class HttpServerConfig
@@ -47,6 +48,7 @@ namespace EggLink.DanhengServer.Configuration
public string DatabasePath { get; set; } = "Config/Database";
public string LogPath { get; set; } = "Logs";
public string PluginPath { get; set; } = "Plugins";
+ public string PluginConfigPath { get; set; } = "Plugins/Config";
}
public class DatabaseConfig
@@ -98,4 +100,9 @@ namespace EggLink.DanhengServer.Configuration
public string? LuaUrl { get; set; } = null;
public string? IfixUrl { get; set; } = null;
}
+
+ public class MuipServerConfig
+ {
+ public string AdminKey { get; set; } = "";
+ }
}
diff --git a/Common/Data/Excel/RogueNPCDialogueExcel.cs b/Common/Data/Excel/RogueNPCDialogueExcel.cs
index b1cbde7d..1a9ad473 100644
--- a/Common/Data/Excel/RogueNPCDialogueExcel.cs
+++ b/Common/Data/Excel/RogueNPCDialogueExcel.cs
@@ -29,10 +29,10 @@ namespace EggLink.DanhengServer.Data.Excel
GameData.RogueNPCDialogueData.Add(GetId(), this);
}
- public bool CanUseInCommon()
+ public bool CanUseInVer(int version)
{
GameData.RogueHandBookEventData.TryGetValue(HandbookEventID, out var handbookEvent);
- return DialogueInfo != null && handbookEvent != null && handbookEvent.EventTypeList.Contains(100);
+ return DialogueInfo != null && handbookEvent != null && handbookEvent.EventTypeList.Contains(version);
}
}
}
diff --git a/Common/Database/Mail/MailData.cs b/Common/Database/Mail/MailData.cs
new file mode 100644
index 00000000..aa7c164e
--- /dev/null
+++ b/Common/Database/Mail/MailData.cs
@@ -0,0 +1,62 @@
+using EggLink.DanhengServer.Database.Inventory;
+using EggLink.DanhengServer.Proto;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Database.Mail
+{
+ public class MailData : BaseDatabaseDataHelper
+ {
+ public List MailList { get; set; } = [];
+ public List NoticeMailList { get; set; } = [];
+
+ public int NextMailId { get; set; } = 1;
+ }
+
+ public class MailInfo
+ {
+ public int MailID { get; set; }
+ public string SenderName { get; set; } = "";
+ public string Title { get; set; } = "";
+ public string Content { get; set; } = "";
+ public bool IsRead { get; set; }
+ public bool IsStar { get; set; }
+ public long SendTime { get; set; }
+ public long ExpireTime { get; set; }
+ public int TemplateID { get; set; }
+ public MailAttachmentInfo Attachment { get; set; } = new();
+
+ public ClientMail ToProto()
+ {
+ return new()
+ {
+ Id = (uint)MailID,
+ Sender = SenderName,
+ Content = Content,
+ MailType = IsStar ? MailType.Star : MailType.Normal,
+ ExpireTime = ExpireTime,
+ IsRead = IsRead,
+ TemplateId = (uint)TemplateID,
+ Title = Title,
+ Time = SendTime,
+ Attachment = Attachment.ToProto()
+ };
+ }
+ }
+
+ public class MailAttachmentInfo
+ {
+ public List Items { get; set; } = [];
+
+ public ItemList ToProto()
+ {
+ return new()
+ {
+ ItemList_ = { Items.Select(x => x.ToProto()).ToList() }
+ };
+ }
+ }
+}
diff --git a/Common/Internationalization/I18nManager.cs b/Common/Internationalization/I18nManager.cs
index fc2aaf0d..dd01e44b 100644
--- a/Common/Internationalization/I18nManager.cs
+++ b/Common/Internationalization/I18nManager.cs
@@ -21,7 +21,9 @@ namespace EggLink.DanhengServer.Internationalization
var languageType = Type.GetType(languageStr);
if (languageType == null)
{
- throw new Exception("Language not found");
+ Logger.Error("Language not found, fallback to EN");
+ // fallback to English
+ languageType = Type.GetType("EggLink.DanhengServer.Internationalization.Message.LanguageEN")!;
}
var language = Activator.CreateInstance(languageType) ?? throw new Exception("Language not found");
Language = language;
diff --git a/Common/Internationalization/Message/LanguageCHS.cs b/Common/Internationalization/Message/LanguageCHS.cs
index 29b429f4..ddb26da5 100644
--- a/Common/Internationalization/Message/LanguageCHS.cs
+++ b/Common/Internationalization/Message/LanguageCHS.cs
@@ -79,6 +79,7 @@ namespace EggLink.DanhengServer.Internationalization.Message
public RogueTextCHS Rogue { get; } = new();
public SceneTextCHS Scene { get; } = new();
public UnlockAllTextCHS UnlockAll { get; } = new();
+ public MailTextCHS Mail { get; } = new();
}
#endregion
@@ -282,6 +283,17 @@ namespace EggLink.DanhengServer.Internationalization.Message
public string SceneReloaded { get; } = "场景已重新加载!";
}
+ ///
+ /// path: Game.Command.Mail
+ ///
+ public class MailTextCHS
+ {
+ public string Desc { get; } = "管理玩家的邮件";
+ public string Usage { get; } = "/mail /";
+ public string MailSent { get; } = "邮件已发送!";
+ public string MailSentWithAttachment { get; } = "带附件的邮件已发送!";
+ }
+
#endregion
#endregion
diff --git a/Common/Util/ConfigManager.cs b/Common/Util/ConfigManager.cs
index f7413242..651a2ebd 100644
--- a/Common/Util/ConfigManager.cs
+++ b/Common/Util/ConfigManager.cs
@@ -14,6 +14,8 @@ namespace EggLink.DanhengServer.Util
{
logger.Warn("Config file not found, creating a new one");
Config = new ConfigContainer();
+ Config.MuipServer.AdminKey = Guid.NewGuid().ToString();
+ logger.Info("Muipserver Admin key: " + Config.MuipServer.AdminKey);
SaveConfig();
}
using (var reader = new StreamReader(file.OpenRead()))
diff --git a/DanhengServer.sln b/DanhengServer.sln
index 66f9e59b..aa3594d8 100644
--- a/DanhengServer.sln
+++ b/DanhengServer.sln
@@ -19,6 +19,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Command", "Command\Command.csproj", "{B52B8DE8-E63E-4CE4-A75F-C17A97C86D89}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Program", "Program\Program.csproj", "{71D8488F-CAED-48EE-BD5C-F325FBAB991F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -37,6 +41,14 @@ Global
{8E3A0EA5-F4BC-4478-AEB9-CAAC07F10BD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E3A0EA5-F4BC-4478-AEB9-CAAC07F10BD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E3A0EA5-F4BC-4478-AEB9-CAAC07F10BD3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B52B8DE8-E63E-4CE4-A75F-C17A97C86D89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B52B8DE8-E63E-4CE4-A75F-C17A97C86D89}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B52B8DE8-E63E-4CE4-A75F-C17A97C86D89}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B52B8DE8-E63E-4CE4-A75F-C17A97C86D89}.Release|Any CPU.Build.0 = Release|Any CPU
+ {71D8488F-CAED-48EE-BD5C-F325FBAB991F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {71D8488F-CAED-48EE-BD5C-F325FBAB991F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {71D8488F-CAED-48EE-BD5C-F325FBAB991F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {71D8488F-CAED-48EE-BD5C-F325FBAB991F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/GameServer/Command/CommandExecutor.cs b/GameServer/Command/CommandExecutor.cs
new file mode 100644
index 00000000..f731e818
--- /dev/null
+++ b/GameServer/Command/CommandExecutor.cs
@@ -0,0 +1,20 @@
+using EggLink.DanhengServer.Command;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.GameServer.Command
+{
+ public static class CommandExecutor
+ {
+ public delegate void RunCommand(ICommandSender sender, string cmd);
+ public static event RunCommand? OnRunCommand;
+
+ public static void ExecuteCommand(ICommandSender sender, string cmd)
+ {
+ OnRunCommand?.Invoke(sender, cmd);
+ }
+ }
+}
diff --git a/GameServer/Command/CommandSender.cs b/GameServer/Command/PlayerCommandSender.cs
similarity index 65%
rename from GameServer/Command/CommandSender.cs
rename to GameServer/Command/PlayerCommandSender.cs
index ea951724..1902f655 100644
--- a/GameServer/Command/CommandSender.cs
+++ b/GameServer/Command/PlayerCommandSender.cs
@@ -1,5 +1,6 @@
-using EggLink.DanhengServer.Database;
+using EggLink.DanhengServer.Command;
using EggLink.DanhengServer.Database.Account;
+using EggLink.DanhengServer.Database;
using EggLink.DanhengServer.Game.Player;
using EggLink.DanhengServer.Server.Packet.Send.Friend;
using EggLink.DanhengServer.Util;
@@ -9,28 +10,8 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace EggLink.DanhengServer.Command
+namespace EggLink.DanhengServer.GameServer.Command
{
- public interface ICommandSender
- {
- public void SendMsg(string msg);
-
- public bool HasPermission(string permission);
- }
-
- public class ConsoleCommandSender(Logger logger) : ICommandSender
- {
- public void SendMsg(string msg)
- {
- logger.Info(msg);
- }
-
- public bool HasPermission(string permission)
- {
- return true;
- }
- }
-
public class PlayerCommandSender(PlayerInstance player) : ICommandSender
{
public PlayerInstance Player = player;
@@ -45,5 +26,10 @@ namespace EggLink.DanhengServer.Command
var account = DatabaseHelper.Instance!.GetInstance(Player.Uid)!;
return account.Permissions!.Contains(permission);
}
+
+ public int GetSender()
+ {
+ return Player.Uid;
+ }
}
}
diff --git a/GameServer/Game/Challenge/ChallengeInstance.cs b/GameServer/Game/Challenge/ChallengeInstance.cs
index e2b46dd3..56b7fc38 100644
--- a/GameServer/Game/Challenge/ChallengeInstance.cs
+++ b/GameServer/Game/Challenge/ChallengeInstance.cs
@@ -330,7 +330,7 @@ namespace EggLink.DanhengServer.Game.Challenge
if (StoryBuffs != null && StoryBuffs.Count >= CurrentStage)
{
- proto.PlayerInfo.CurStoryBuff.BuffList.Add((uint)StoryBuffs[CurrentStage - 1]);
+ proto.PlayerInfo.CurStoryBuff.BuffList.Add(StoryBuffs.Select(x => (uint)x));
}
// Early implementation for 2.3
diff --git a/GameServer/Game/Challenge/ChallengeManager.cs b/GameServer/Game/Challenge/ChallengeManager.cs
index 7cee0ae7..cd258e44 100644
--- a/GameServer/Game/Challenge/ChallengeManager.cs
+++ b/GameServer/Game/Challenge/ChallengeManager.cs
@@ -24,12 +24,12 @@ namespace EggLink.DanhengServer.Game.Challenge
public void StartChallenge(int challengeId, StartChallengeStoryBuffInfo? storyBuffs)
{
// Get challenge excel
- if (!GameData.ChallengeConfigData.ContainsKey(challengeId))
+ if (!GameData.ChallengeConfigData.TryGetValue(challengeId, out ChallengeConfigExcel? value))
{
Player.SendPacket(new PacketStartChallengeScRsp((uint)Retcode.RetChallengeNotExist));
return;
}
- ChallengeConfigExcel Excel = GameData.ChallengeConfigData[challengeId];
+ ChallengeConfigExcel Excel = value;
// Sanity check lineups
if (Excel.StageNum > 0)
@@ -79,7 +79,7 @@ namespace EggLink.DanhengServer.Game.Challenge
}
// Set challenge data for player
- ChallengeInstance instance = new ChallengeInstance(Player, Excel);
+ ChallengeInstance instance = new(Player, Excel);
ChallengeInstance = instance;
// Set first lineup before we enter scenes
@@ -88,7 +88,7 @@ namespace EggLink.DanhengServer.Game.Challenge
// Enter scene
try
{
- Player.EnterScene(Excel.MapEntranceID, 0, true);
+ Player.EnterScene(Excel.MapEntranceID, 0, false);
}
catch
{
@@ -257,9 +257,9 @@ namespace EggLink.DanhengServer.Game.Challenge
if (ChallengeData.Instance != null && ChallengeData.Instance.ChallengeId != 0)
{
int ChallengeId = ChallengeData.Instance.ChallengeId;
- if (GameData.ChallengeConfigData.ContainsKey(ChallengeId))
+ if (GameData.ChallengeConfigData.TryGetValue(ChallengeId, out ChallengeConfigExcel? value))
{
- ChallengeConfigExcel Excel = GameData.ChallengeConfigData[ChallengeId];
+ ChallengeConfigExcel Excel = value;
ChallengeInstance instance = new ChallengeInstance(Player, Excel, ChallengeData.Instance);
ChallengeInstance = instance;
}
diff --git a/GameServer/Game/ChessRogue/ChessRogueInstance.cs b/GameServer/Game/ChessRogue/ChessRogueInstance.cs
index 0c082584..8fc7721e 100644
--- a/GameServer/Game/ChessRogue/ChessRogueInstance.cs
+++ b/GameServer/Game/ChessRogue/ChessRogueInstance.cs
@@ -48,6 +48,14 @@ namespace EggLink.DanhengServer.Game.ChessRogue
CurLayer = Layers.First();
EventManager = new(player, this);
+ if (rogueVersionId == 202)
+ {
+ RogueType = 160;
+ } else
+ {
+ RogueType = 130;
+ }
+
foreach (var difficulty in areaExcel.DifficultyID)
{
if (GameData.RogueDLCDifficultyData.TryGetValue(difficulty, out var diff))
diff --git a/GameServer/Game/Friend/FriendManager.cs b/GameServer/Game/Friend/FriendManager.cs
index 54c2da1f..779afacc 100644
--- a/GameServer/Game/Friend/FriendManager.cs
+++ b/GameServer/Game/Friend/FriendManager.cs
@@ -4,7 +4,7 @@ using EggLink.DanhengServer.Database.Friend;
using EggLink.DanhengServer.Database.Inventory;
using EggLink.DanhengServer.Database.Player;
using EggLink.DanhengServer.Game.Player;
-using EggLink.DanhengServer.Program;
+using EggLink.DanhengServer.GameServer.Command;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Server;
using EggLink.DanhengServer.Server.Packet.Send.Friend;
@@ -162,7 +162,7 @@ namespace EggLink.DanhengServer.Game.Friend
if (message?.StartsWith('/') == true)
{
var cmd = message[1..];
- EntryPoint.CommandManager.HandleCommand(cmd, new PlayerCommandSender(Player));
+ CommandExecutor.ExecuteCommand(new PlayerCommandSender(Player), cmd);
}
}
diff --git a/GameServer/Game/Inventory/InventoryManager.cs b/GameServer/Game/Inventory/InventoryManager.cs
index f0955ed7..ef3b7520 100644
--- a/GameServer/Game/Inventory/InventoryManager.cs
+++ b/GameServer/Game/Inventory/InventoryManager.cs
@@ -38,7 +38,7 @@ namespace EggLink.DanhengServer.Game.Inventory
var syncItems = new List();
foreach (var item in items)
{
- var i = AddItem(item.ItemId, items.Count, false, sync:false, returnRaw:true);
+ var i = AddItem(item.ItemId, item.Count, false, sync:false, returnRaw:true);
if (i != null)
{
syncItems.Add(i);
diff --git a/GameServer/Game/Mail/MailManager.cs b/GameServer/Game/Mail/MailManager.cs
new file mode 100644
index 00000000..fc823325
--- /dev/null
+++ b/GameServer/Game/Mail/MailManager.cs
@@ -0,0 +1,96 @@
+using EggLink.DanhengServer.Database;
+using EggLink.DanhengServer.Database.Inventory;
+using EggLink.DanhengServer.Database.Mail;
+using EggLink.DanhengServer.Game;
+using EggLink.DanhengServer.Game.Player;
+using EggLink.DanhengServer.GameServer.Server.Packet.Send.Mail;
+using EggLink.DanhengServer.Proto;
+using EggLink.DanhengServer.Util;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Mail;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.GameServer.Game.Mail
+{
+ public class MailManager(PlayerInstance player) : BasePlayerManager(player)
+ {
+ public MailData MailData { get; private set; } = DatabaseHelper.Instance!.GetInstanceOrCreateNew(player.Uid);
+
+ public List GetMailList()
+ {
+ return MailData.MailList;
+ }
+
+ public MailInfo? GetMail(int mailId)
+ {
+ return MailData.MailList.Find(x => x.MailID == mailId);
+ }
+
+ public void SendMail(string sender, string title, string content, int templateId, int expiredDay = 30)
+ {
+ var mail = new MailInfo()
+ {
+ MailID = MailData.NextMailId++,
+ SenderName = sender,
+ Content = content,
+ Title = title,
+ TemplateID = templateId,
+ SendTime = DateTime.Now.ToUnixSec(),
+ ExpireTime = DateTime.Now.AddDays(expiredDay).ToUnixSec(),
+ };
+
+ MailData.MailList.Add(mail);
+
+ Player.SendPacket(new PacketNewMailScNotify(mail.MailID));
+ }
+
+ public void SendMail(string sender, string title, string content, int templateId, List attachments, int expiredDay = 30)
+ {
+ var mail = new MailInfo()
+ {
+ MailID = MailData.NextMailId++,
+ SenderName = sender,
+ Content = content,
+ Title = title,
+ TemplateID = templateId,
+ SendTime = DateTime.Now.ToUnixSec(),
+ ExpireTime = DateTime.Now.AddDays(expiredDay).ToUnixSec(),
+ Attachment = new()
+ {
+ Items = attachments
+ }
+ };
+
+ MailData.MailList.Add(mail);
+
+ Player.SendPacket(new PacketNewMailScNotify(mail.MailID));
+ }
+
+ public List ToMailProto()
+ {
+ var list = new List();
+
+ foreach (var mail in MailData.MailList)
+ {
+ list.Add(mail.ToProto());
+ }
+
+ return list;
+ }
+
+ public List ToNoticeMailProto()
+ {
+ var list = new List();
+
+ foreach (var mail in MailData.NoticeMailList)
+ {
+ list.Add(mail.ToProto());
+ }
+
+ return list;
+ }
+ }
+}
diff --git a/GameServer/Game/Player/PlayerInstance.cs b/GameServer/Game/Player/PlayerInstance.cs
index cec7e578..3165c7bd 100644
--- a/GameServer/Game/Player/PlayerInstance.cs
+++ b/GameServer/Game/Player/PlayerInstance.cs
@@ -35,6 +35,7 @@ using EggLink.DanhengServer.Game.Drop;
using static EggLink.DanhengServer.Plugin.Event.PluginEvent;
using EggLink.DanhengServer.Plugin.Event;
using EggLink.DanhengServer.Game.Task;
+using EggLink.DanhengServer.GameServer.Game.Mail;
namespace EggLink.DanhengServer.Game.Player
{
@@ -51,6 +52,7 @@ namespace EggLink.DanhengServer.Game.Player
public MissionManager? MissionManager { get; private set; }
public GachaManager? GachaManager { get; private set; }
public MessageManager? MessageManager { get; private set; }
+ public MailManager? MailManager { get; private set; }
public FriendManager? FriendManager { get; private set; }
public RogueManager? RogueManager { get; private set; }
@@ -124,6 +126,7 @@ namespace EggLink.DanhengServer.Game.Player
MissionManager = new(this);
GachaManager = new(this);
MessageManager = new(this);
+ MailManager = new(this);
FriendManager = new(this);
RogueManager = new(this);
ShopService = new(this);
@@ -508,6 +511,10 @@ namespace EggLink.DanhengServer.Game.Player
{
EnterScene(OldEntryId > 0 ? OldEntryId : 2000101, 0, sendPacket);
return;
+ } else if (plane.PlaneType == PlaneTypeEnum.Challenge && ChallengeManager!.ChallengeInstance == null)
+ {
+ EnterScene(100000103, 0, sendPacket);
+ return;
}
// TODO: Sanify check
diff --git a/GameServer/Game/Rogue/BaseRogueInstance.cs b/GameServer/Game/Rogue/BaseRogueInstance.cs
index 9770828b..600a012d 100644
--- a/GameServer/Game/Rogue/BaseRogueInstance.cs
+++ b/GameServer/Game/Rogue/BaseRogueInstance.cs
@@ -19,6 +19,7 @@ namespace EggLink.DanhengServer.Game.Rogue
public PlayerInstance Player { get; set; } = player;
public Database.Lineup.LineupInfo? CurLineup { get; set; }
public int RogueVersionId { get; set; } = rogueVersionId;
+ public int RogueType { get; set; } = 100;
public int CurReviveCost { get; set; } = 80;
public int CurRerollCost { get; set; } = 30;
public int BaseRerollCount { get; set; } = 1;
@@ -406,7 +407,7 @@ namespace EggLink.DanhengServer.Game.Rogue
do
{
dialogue = GameData.RogueNPCDialogueData.Values.ToList().RandomElement();
- } while (dialogue == null || !dialogue.CanUseInCommon());
+ } while (dialogue == null || !dialogue.CanUseInVer(RogueType));
var instance = new RogueEventInstance(dialogue, npc, CurEventUniqueID++);
EventManager?.AddEvent(instance);
diff --git a/GameServer/Game/Rogue/Event/RogueEventInstance.cs b/GameServer/Game/Rogue/Event/RogueEventInstance.cs
index 7b26bde5..add5e52c 100644
--- a/GameServer/Game/Rogue/Event/RogueEventInstance.cs
+++ b/GameServer/Game/Rogue/Event/RogueEventInstance.cs
@@ -51,7 +51,7 @@ namespace EggLink.DanhengServer.Game.Rogue.Event
var proto = new DialogueEvent()
{
EventId = (uint)EventId,
- GameModeType = (uint)EventEntity.Scene.Excel.PlaneType,
+ GameModeType = (uint)(EventEntity.Scene.CustomGameModeId > 0 ? EventEntity.Scene.CustomGameModeId : (int)EventEntity.Scene.Excel.PlaneType),
EventUniqueId = (uint)EventUniqueId,
};
diff --git a/GameServer/Game/Scene/SceneInstance.cs b/GameServer/Game/Scene/SceneInstance.cs
index 7e95c4a9..17248949 100644
--- a/GameServer/Game/Scene/SceneInstance.cs
+++ b/GameServer/Game/Scene/SceneInstance.cs
@@ -61,7 +61,7 @@ namespace EggLink.DanhengServer.Game.Scene
if (Player.ChessRogueManager!.RogueInstance != null)
{
EntityLoader = new ChessRogueEntityLoader(this);
- CustomGameModeId = 16;
+ CustomGameModeId = 16; // ChessRogue
} else
{
EntityLoader = new RogueEntityLoader(this, Player);
diff --git a/GameServer/GameServer.csproj b/GameServer/GameServer.csproj
index 4dc7898e..af4ae494 100644
--- a/GameServer/GameServer.csproj
+++ b/GameServer/GameServer.csproj
@@ -1,14 +1,14 @@
- Exe
+ Library
net8.0
enable
enable
- EggLink.DanhengServer
- EggLink.DanhengServer.Program.EntryPoint
+ EggLink.DanhengServer.GameServer
+
true
- DanhengServer
+ DanhengGameServer
@@ -17,12 +17,12 @@
-
-
+
+
diff --git a/GameServer/Plugin/Constructor/IPlugin.cs b/GameServer/Plugin/Constructor/IPlugin.cs
index 76c927ef..1e3a37ca 100644
--- a/GameServer/Plugin/Constructor/IPlugin.cs
+++ b/GameServer/Plugin/Constructor/IPlugin.cs
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
namespace EggLink.DanhengServer.Plugin.Constructor
{
+ [Obsolete("以俟君子 Wait for someone to develop it")]
public interface IPlugin
{
public void OnLoad();
diff --git a/GameServer/Plugin/Constructor/PluginInfo.cs b/GameServer/Plugin/Constructor/PluginInfo.cs
new file mode 100644
index 00000000..19a7c632
--- /dev/null
+++ b/GameServer/Plugin/Constructor/PluginInfo.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Plugin.Constructor
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class PluginInfo(string name, string description, string version) : Attribute
+ {
+ public string Name { get; } = name;
+ public string Description { get; } = description;
+ public string Version { get; } = version;
+ }
+}
diff --git a/GameServer/Plugin/PluginManager.cs b/GameServer/Plugin/PluginManager.cs
index 66ba4c90..980e304c 100644
--- a/GameServer/Plugin/PluginManager.cs
+++ b/GameServer/Plugin/PluginManager.cs
@@ -1,7 +1,10 @@
using EggLink.DanhengServer.Plugin.Constructor;
using EggLink.DanhengServer.Util;
+using McMaster.NETCore.Plugins;
+using Newtonsoft.Json;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
@@ -12,10 +15,12 @@ namespace EggLink.DanhengServer.Plugin
public class PluginManager
{
private readonly static Logger logger = new("PluginManager");
- public readonly static List Plugins = [];
+ public readonly static Dictionary Plugins = [];
public readonly static Dictionary> PluginAssemblies = [];
+ #region Plugin Manager
+
public static void LoadPlugins()
{
// get all the plugins in the plugin directory
@@ -24,43 +29,81 @@ namespace EggLink.DanhengServer.Plugin
Directory.CreateDirectory(ConfigManager.Config.Path.PluginPath);
}
+ if (!Directory.Exists(ConfigManager.Config.Path.PluginConfigPath))
+ {
+ Directory.CreateDirectory(ConfigManager.Config.Path.PluginConfigPath);
+ }
+
var plugins = Directory.GetFiles(ConfigManager.Config.Path.PluginPath, "*.dll");
+ var loaders = new List();
+ AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
+ {
+ var assemblyName = new AssemblyName(args.Name).Name + ".dll";
+ var assemblyPath = Path.Combine(ConfigManager.Config.Path.PluginPath, assemblyName);
+
+ if (File.Exists(assemblyPath))
+ {
+ return Assembly.LoadFrom(assemblyPath);
+ }
+
+ return null;
+ };
foreach (var plugin in plugins)
{
var fileInfo = new FileInfo(plugin);
LoadPlugin(fileInfo.FullName);
}
-
- logger.Info($"Loaded {Plugins.Count} plugins");
}
public static void LoadPlugin(string plugin)
{
try
{
- var assembly = Assembly.LoadFile(plugin);
+ var config = new PluginConfig(plugin)
+ {
+ PreferSharedTypes = true,
+ LoadInMemory = true,
+ };
+
+ var loader = new PluginLoader(config);
+
+ var assembly = loader.LoadDefaultAssembly();
var types = assembly.GetTypes();
- bool isPlugin = false;
foreach (var type in types)
{
- if (type.GetInterface("IPlugin") != null)
+ if (typeof(IPlugin).IsAssignableFrom(type))
{
if (Activator.CreateInstance(type) is IPlugin pluginInstance)
{
- pluginInstance.OnLoad();
- Plugins.Add(pluginInstance);
-
- if (!PluginAssemblies.TryGetValue(pluginInstance, out List? value))
+ var pluginInfo = type.GetCustomAttribute();
+ if (pluginInfo != null)
{
- value = new List();
- PluginAssemblies[pluginInstance] = value;
+ logger.Info($"Loaded plugin {pluginInfo.Name} v{pluginInfo.Version}: {pluginInfo.Description}");
+ }
+ else
+ {
+ logger.Info($"Loaded plugin {plugin}: No plugin info");
+ continue;
}
- value.AddRange(types);
+ if (Plugins.Values.Any(p => p.Name == pluginInfo.Name))
+ {
+ logger.Error($"Failed to load plugin {plugin}: Plugin already loaded");
+ continue;
+ }
- isPlugin = true;
- break;
+ Plugins.Add(pluginInstance, pluginInfo);
+
+ if (!PluginAssemblies.TryGetValue(pluginInstance, out var pluginTypes))
+ {
+ pluginTypes = [];
+ PluginAssemblies[pluginInstance] = pluginTypes;
+ }
+
+ pluginTypes.AddRange(types);
+
+ pluginInstance.OnLoad();
}
else
{
@@ -68,33 +111,41 @@ namespace EggLink.DanhengServer.Plugin
}
}
}
-
- if (!isPlugin)
- {
- logger.Error($"Failed to load plugin {plugin}: Plugin does not implement IPlugin");
- }
}
- catch (Exception e)
+ catch (Exception ex)
{
- logger.Error($"Failed to load plugin {plugin}: {e.Message}");
+ logger.Error($"Failed to load plugin {plugin}: {ex.Message}");
}
}
+ public static void UnloadPlugin(IPlugin plugin)
+ {
+ if (Plugins.TryGetValue(plugin, out PluginInfo? value))
+ {
+ plugin.OnUnload();
+ Plugins.Remove(plugin);
+ PluginAssemblies.Remove(plugin);
+ logger.Info($"Unloaded plugin {value.Name}");
+ }
+ }
+
+
public static void UnloadPlugins()
{
- foreach (var plugin in Plugins)
+ foreach (var plugin in Plugins.Keys)
{
- plugin.OnUnload();
+ UnloadPlugin(plugin);
}
logger.Info("Unloaded all plugins");
- Plugins.Clear();
}
+ #endregion
+
public static List GetPluginAssemblies()
{
var assemblies = new List();
- foreach (var plugin in Plugins)
+ foreach (var plugin in Plugins.Keys)
{
if (PluginAssemblies.TryGetValue(plugin, out List? value))
{
diff --git a/GameServer/Server/Connection.cs b/GameServer/Server/Connection.cs
index 0aa5bfe5..646608a1 100644
--- a/GameServer/Server/Connection.cs
+++ b/GameServer/Server/Connection.cs
@@ -5,7 +5,6 @@ using System.Reflection;
using EggLink.DanhengServer.Common.Enums;
using EggLink.DanhengServer.Game.Player;
using EggLink.DanhengServer.KcpSharp;
-using EggLink.DanhengServer.Program;
using EggLink.DanhengServer.Server.Packet;
using EggLink.DanhengServer.Util;
using Google.Protobuf;
@@ -70,7 +69,7 @@ public partial class Connection
}
#pragma warning disable CS8600
Type? typ = AppDomain.CurrentDomain.GetAssemblies().
- SingleOrDefault(assembly => assembly.GetName().Name == "Common")!.GetTypes().First(t => t.Name == $"{LogMap[opcode.ToString()]}"); //get the type using the packet name
+ SingleOrDefault(assembly => assembly.GetName().Name == "DanhengCommon")!.GetTypes().First(t => t.Name == $"{LogMap[opcode.ToString()]}"); //get the type using the packet name
MessageDescriptor? descriptor = (MessageDescriptor)typ.GetProperty("Descriptor", BindingFlags.Public | BindingFlags.Static)!.GetValue(null, null); // get the static property Descriptor
IMessage? packet = descriptor!.Parser.ParseFrom(payload);
#pragma warning restore CS8600
@@ -178,7 +177,7 @@ public partial class Connection
private bool HandlePacket(ushort opcode, byte[] header, byte[] payload)
{
// Find the Handler for this opcode
- Handler? handler = EntryPoint.HandlerManager.GetHandler(opcode);
+ Handler? handler = HandlerManager.GetHandler(opcode);
if (handler != null)
{
// Handle
diff --git a/GameServer/Server/Packet/HandlerManager.cs b/GameServer/Server/Packet/HandlerManager.cs
index 6f7e9740..eda16bcf 100644
--- a/GameServer/Server/Packet/HandlerManager.cs
+++ b/GameServer/Server/Packet/HandlerManager.cs
@@ -2,11 +2,11 @@
namespace EggLink.DanhengServer.Server.Packet
{
- public class HandlerManager
+ public static class HandlerManager
{
- public Dictionary handlers = [];
+ public static Dictionary handlers = [];
- public HandlerManager()
+ public static void Init()
{
var classes = Assembly.GetExecutingAssembly().GetTypes(); // Get all classes in the assembly
foreach (var cls in classes)
@@ -20,7 +20,7 @@ namespace EggLink.DanhengServer.Server.Packet
}
}
- public Handler? GetHandler(int cmdId)
+ public static Handler? GetHandler(int cmdId)
{
try
{
diff --git a/GameServer/Server/Packet/Recv/Friend/HandlerSendMsgCsReq.cs b/GameServer/Server/Packet/Recv/Friend/HandlerSendMsgCsReq.cs
index afd1a236..48d95d81 100644
--- a/GameServer/Server/Packet/Recv/Friend/HandlerSendMsgCsReq.cs
+++ b/GameServer/Server/Packet/Recv/Friend/HandlerSendMsgCsReq.cs
@@ -1,5 +1,4 @@
using EggLink.DanhengServer.Command;
-using EggLink.DanhengServer.Program;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Server.Packet.Send.Friend;
using EggLink.DanhengServer.Server.Packet.Send.Gacha;
diff --git a/GameServer/Server/Packet/Recv/Mail/HandlerGetMailCsReq.cs b/GameServer/Server/Packet/Recv/Mail/HandlerGetMailCsReq.cs
new file mode 100644
index 00000000..150b72d2
--- /dev/null
+++ b/GameServer/Server/Packet/Recv/Mail/HandlerGetMailCsReq.cs
@@ -0,0 +1,20 @@
+using EggLink.DanhengServer.GameServer.Server.Packet.Send.Mail;
+using EggLink.DanhengServer.Server;
+using EggLink.DanhengServer.Server.Packet;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Mail
+{
+ [Opcode(CmdIds.GetMailCsReq)]
+ public class HandlerGetMailCsReq : Handler
+ {
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
+ {
+ connection.SendPacket(new PacketGetMailScRsp(connection.Player!));
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Recv/Mail/HandlerMarkReadMailCsReq.cs b/GameServer/Server/Packet/Recv/Mail/HandlerMarkReadMailCsReq.cs
new file mode 100644
index 00000000..13f3e6bf
--- /dev/null
+++ b/GameServer/Server/Packet/Recv/Mail/HandlerMarkReadMailCsReq.cs
@@ -0,0 +1,33 @@
+using EggLink.DanhengServer.GameServer.Server.Packet.Send.Mail;
+using EggLink.DanhengServer.Proto;
+using EggLink.DanhengServer.Server;
+using EggLink.DanhengServer.Server.Packet;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Mail
+{
+ [Opcode(CmdIds.MarkReadMailCsReq)]
+ public class HandlerMarkReadMailCsReq : Handler
+ {
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
+ {
+ var req = MarkReadMailCsReq.Parser.ParseFrom(data);
+ var player = connection.Player!;
+
+ var mail = player.MailManager!.GetMail((int)req.Id);
+
+ if (mail != null)
+ {
+ mail.IsRead = true;
+ connection.SendPacket(new PacketMarkReadMailScRsp(req.Id));
+ } else
+ {
+ connection.SendPacket(new PacketMarkReadMailScRsp(Retcode.RetMailMailIdInvalid));
+ }
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Challenge/PacketStartChallengeScRsp.cs b/GameServer/Server/Packet/Send/Challenge/PacketStartChallengeScRsp.cs
index 4f10bfe8..044d5dac 100644
--- a/GameServer/Server/Packet/Send/Challenge/PacketStartChallengeScRsp.cs
+++ b/GameServer/Server/Packet/Send/Challenge/PacketStartChallengeScRsp.cs
@@ -17,13 +17,15 @@ namespace EggLink.DanhengServer.Server.Packet.Send.Challenge
public PacketStartChallengeScRsp(PlayerInstance player) : base(CmdIds.StartChallengeScRsp)
{
- StartChallengeScRsp proto = new StartChallengeScRsp() { };
+ StartChallengeScRsp proto = new()
+ {
+ };
if (player.ChallengeManager!.ChallengeInstance != null)
{
proto.CurChallenge = player.ChallengeManager.ChallengeInstance.ToProto();
proto.Lineup = player.LineupManager!.GetExtraLineup(ExtraLineupType.LineupChallenge)!.ToProto(); // Deprecated in 2.3
-
+ proto.Scene = player.SceneInstance!.ToProto();
// Early implementation for 2.3
/* proto.LineupList.Add(player.LineupManager!.GetExtraLineup(ExtraLineupType.LineupChallenge)!.ToProto());
proto.Lineup.Add(player.LineupManager!.GetExtraLineup(ExtraLineupType.LineupChallenge2)!.ToProto()); */
diff --git a/GameServer/Server/Packet/Send/Mail/PacketGetMailScRsp.cs b/GameServer/Server/Packet/Send/Mail/PacketGetMailScRsp.cs
new file mode 100644
index 00000000..f0494452
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Mail/PacketGetMailScRsp.cs
@@ -0,0 +1,29 @@
+using EggLink.DanhengServer.Game.Player;
+using EggLink.DanhengServer.Proto;
+using EggLink.DanhengServer.Server.Packet;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Mail
+{
+ public class PacketGetMailScRsp : BasePacket
+ {
+ public PacketGetMailScRsp(PlayerInstance player) : base(CmdIds.GetMailScRsp)
+ {
+ var list = player.MailManager!.ToMailProto();
+ var noticeList = player.MailManager!.ToNoticeMailProto();
+ var proto = new GetMailScRsp
+ {
+ IsEnd = true,
+ MailList = { list },
+ NoticeMailList = { noticeList },
+ TotalNum = (uint)(list.Count + noticeList.Count)
+ };
+
+ SetData(proto);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Mail/PacketMarkReadMailScRsp.cs b/GameServer/Server/Packet/Send/Mail/PacketMarkReadMailScRsp.cs
new file mode 100644
index 00000000..60327b30
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Mail/PacketMarkReadMailScRsp.cs
@@ -0,0 +1,33 @@
+using EggLink.DanhengServer.Proto;
+using EggLink.DanhengServer.Server.Packet;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Mail
+{
+ public class PacketMarkReadMailScRsp : BasePacket
+ {
+ public PacketMarkReadMailScRsp(uint mailId) : base(CmdIds.MarkReadMailScRsp)
+ {
+ var proto = new MarkReadMailScRsp()
+ {
+ Id = mailId
+ };
+
+ SetData(proto);
+ }
+
+ public PacketMarkReadMailScRsp(Retcode retcode) : base(CmdIds.MarkReadMailScRsp)
+ {
+ var proto = new MarkReadMailScRsp()
+ {
+ Retcode = (uint)retcode
+ };
+
+ SetData(proto);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Mail/PacketNewMailScNotify.cs b/GameServer/Server/Packet/Send/Mail/PacketNewMailScNotify.cs
new file mode 100644
index 00000000..9e55282f
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Mail/PacketNewMailScNotify.cs
@@ -0,0 +1,23 @@
+using EggLink.DanhengServer.Proto;
+using EggLink.DanhengServer.Server.Packet;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Mail
+{
+ public class PacketNewMailScNotify : BasePacket
+ {
+ public PacketNewMailScNotify(int id) : base(CmdIds.NewMailScNotify)
+ {
+ var proto = new NewMailScNotify()
+ {
+ MailIdList = { (uint)id }
+ };
+
+ SetData(proto);
+ }
+ }
+}
diff --git a/GameServer/Handbook/HandbookGenerator.cs b/Program/Handbook/HandbookGenerator.cs
similarity index 100%
rename from GameServer/Handbook/HandbookGenerator.cs
rename to Program/Handbook/HandbookGenerator.cs
diff --git a/Program/Program.csproj b/Program/Program.csproj
new file mode 100644
index 00000000..ec844455
--- /dev/null
+++ b/Program/Program.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ EggLink.DanhengServer.Program
+ DanhengServer
+
+
+
+
+
+
+
+
+
+
diff --git a/GameServer/Program/EntryPoint.cs b/Program/Program/EntryPoint.cs
similarity index 85%
rename from GameServer/Program/EntryPoint.cs
rename to Program/Program/EntryPoint.cs
index 7e358e15..a3e1c526 100644
--- a/GameServer/Program/EntryPoint.cs
+++ b/Program/Program/EntryPoint.cs
@@ -4,13 +4,15 @@ using EggLink.DanhengServer.Configuration;
using EggLink.DanhengServer.WebServer;
using EggLink.DanhengServer.Database;
using EggLink.DanhengServer.Server;
-using EggLink.DanhengServer.Server.Packet;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
-using EggLink.DanhengServer.Command;
using EggLink.DanhengServer.Handbook;
using EggLink.DanhengServer.Internationalization;
using EggLink.DanhengServer.Plugin;
+using EggLink.DanhengServer.Command;
+using EggLink.DanhengServer.Server.Packet;
+using EggLink.DanhengServer.GameServer.Command;
+using EggLink.DanhengServer.WebServer.Server;
namespace EggLink.DanhengServer.Program
{
@@ -19,7 +21,6 @@ namespace EggLink.DanhengServer.Program
private readonly static Logger logger = new("Program");
public readonly static DatabaseHelper DatabaseHelper = new();
public readonly static Listener Listener = new();
- public readonly static HandlerManager HandlerManager = new();
public readonly static CommandManager CommandManager = new();
public static void Main(string[] args)
@@ -75,18 +76,6 @@ namespace EggLink.DanhengServer.Program
return;
}
- // Load the plugins
- logger.Info("Loading plugins...");
- try
- {
- PluginManager.LoadPlugins();
- } catch (Exception e)
- {
- logger.Error("Failed to load plugins", e);
- Console.ReadLine();
- return;
- }
-
// Load the game data
logger.Info("Loading game data...");
try
@@ -130,10 +119,32 @@ namespace EggLink.DanhengServer.Program
Console.ReadLine();
return;
}
-
+
+ // Load the plugins
+ logger.Info("Loading plugins...");
+ try
+ {
+ PluginManager.LoadPlugins();
+ }
+ catch (Exception e)
+ {
+ logger.Error("Failed to load plugins", e);
+ Console.ReadLine();
+ return;
+ }
+
+ CommandExecutor.OnRunCommand += (sender, e) =>
+ {
+ CommandManager.HandleCommand(e, sender);
+ };
+
+ MuipManager.OnExecuteCommand += CommandManager.HandleCommand;
+
// generate the handbook
HandbookGenerator.Generate();
+ HandlerManager.Init();
+
WebProgram.Main([], GetConfig().HttpServer.PublicPort, GetConfig().HttpServer.GetDisplayAddress());
logger.Info($"Dispatch Server is running on {GetConfig().HttpServer.GetDisplayAddress()}");
@@ -143,7 +154,7 @@ namespace EggLink.DanhengServer.Program
logger.Info($"Done in {elapsed.TotalSeconds.ToString()[..4]}s! Type '/help' to get help of commands.");
#if DEBUG
- JsonConvert.DeserializeObject(File.ReadAllText("LogMap.json"))!.Properties().ToList().ForEach(x => Connection.LogMap.Add(x.Name, x.Value.ToString()));
+ GenerateLogMap();
#endif
if (GetConfig().ServerOption.EnableMission)
{
@@ -165,5 +176,21 @@ namespace EggLink.DanhengServer.Program
DatabaseHelper.SaveThread?.Interrupt();
DatabaseHelper.SaveDatabase();
}
+
+#if DEBUG
+
+ private static void GenerateLogMap()
+ {
+ // get opcode from CmdIds
+ var opcodes = typeof(CmdIds).GetFields().Where(x => x.FieldType == typeof(int)).ToList();
+ foreach (var opcode in opcodes)
+ {
+ var name = opcode.Name;
+ var value = (int)opcode.GetValue(null)!;
+ Connection.LogMap.Add(value.ToString(), name);
+ }
+ }
+
+#endif
}
}
diff --git a/WebServer/Controllers/GateServerRoutes.cs b/WebServer/Controllers/GateServerRoutes.cs
index a5adfb71..c12d88a5 100644
--- a/WebServer/Controllers/GateServerRoutes.cs
+++ b/WebServer/Controllers/GateServerRoutes.cs
@@ -1,4 +1,4 @@
-using EggLink.DanhengServer.Server.Http.Handler;
+using EggLink.DanhengServer.WebServer.Handler;
using Microsoft.AspNetCore.Mvc;
namespace EggLink.DanhengServer.WebServer.Controllers
diff --git a/WebServer/Controllers/MuipServerRoutes.cs b/WebServer/Controllers/MuipServerRoutes.cs
new file mode 100644
index 00000000..034a170d
--- /dev/null
+++ b/WebServer/Controllers/MuipServerRoutes.cs
@@ -0,0 +1,33 @@
+using EggLink.DanhengServer.Util;
+using EggLink.DanhengServer.WebServer.Request;
+using EggLink.DanhengServer.WebServer.Response;
+using EggLink.DanhengServer.WebServer.Server;
+using Microsoft.AspNetCore.Mvc;
+
+namespace EggLink.DanhengServer.WebServer.Controllers
+{
+ [ApiController]
+ [Route("/")]
+ public class MuipServerRoutes
+ {
+ [HttpGet("/muip/auth_admin")]
+ [HttpPost("/muip/auth_admin")]
+ public IActionResult AuthAdminKey([FromBody] AuthAdminKeyRequestBody req)
+ {
+ var data = MuipManager.AuthAdminAndCreateSession(req.admin_key, req.key_type);
+ if (data == null)
+ {
+ return new JsonResult(new AuthAdminKeyResponse(1, "Admin key is invalid!", null));
+ }
+ return new JsonResult(new AuthAdminKeyResponse(0, "Authorized admin key successfully!", data));
+ }
+
+ [HttpGet("/muip/exec_cmd")]
+ [HttpPost("/muip/exec_cmd")]
+ public IActionResult ExecuteCommand([FromBody] AdminExecRequest req)
+ {
+ var resp = MuipManager.ExecuteCommand(req.SessionId, req.Command, req.TargetUid);
+ return new JsonResult(resp);
+ }
+ }
+}
diff --git a/WebServer/Handler/QueryGatewayHandler.cs b/WebServer/Handler/QueryGatewayHandler.cs
index 5686e3be..24705b6b 100644
--- a/WebServer/Handler/QueryGatewayHandler.cs
+++ b/WebServer/Handler/QueryGatewayHandler.cs
@@ -2,7 +2,7 @@
using EggLink.DanhengServer.Util;
using Google.Protobuf;
-namespace EggLink.DanhengServer.Server.Http.Handler
+namespace EggLink.DanhengServer.WebServer.Handler
{
internal class QueryGatewayHandler
{
@@ -14,7 +14,8 @@ namespace EggLink.DanhengServer.Server.Http.Handler
var urlData = config.DownloadUrl;
// build gateway proto
- var gateServer = new GateServer() {
+ var gateServer = new GateServer()
+ {
RegionName = config.GameServer.GameServerId,
Ip = config.GameServer.PublicAddress,
Port = config.GameServer.PublicPort,
@@ -41,7 +42,7 @@ namespace EggLink.DanhengServer.Server.Http.Handler
gateServer.LuaUrl = urlData.LuaUrl;
gateServer.MdkResVersion = urlData.LuaUrl.Split('/')[^1].Split('_')[1];
}
-
+
if (urlData.IfixUrl != null && urlData.IfixUrl.Length > 0)
{
gateServer.IfixUrl = urlData.IfixUrl;
diff --git a/WebServer/Request/AuthRequest.cs b/WebServer/Request/AuthRequest.cs
new file mode 100644
index 00000000..c9fe819c
--- /dev/null
+++ b/WebServer/Request/AuthRequest.cs
@@ -0,0 +1,8 @@
+namespace EggLink.DanhengServer.WebServer.Request
+{
+ public class AuthAdminKeyRequestBody
+ {
+ public string admin_key { get; set; } = "";
+ public string key_type { get; set; } = "XML";
+ }
+}
diff --git a/WebServer/Request/ExecRequest.cs b/WebServer/Request/ExecRequest.cs
new file mode 100644
index 00000000..1016acf5
--- /dev/null
+++ b/WebServer/Request/ExecRequest.cs
@@ -0,0 +1,9 @@
+namespace EggLink.DanhengServer.WebServer.Request
+{
+ public class AdminExecRequest
+ {
+ public string SessionId { get; set; } = "";
+ public string Command { get; set; } = "";
+ public int TargetUid { get; set; } = 0;
+ }
+}
diff --git a/WebServer/Response/AuthAdminKeyResponse.cs b/WebServer/Response/AuthAdminKeyResponse.cs
new file mode 100644
index 00000000..1679c651
--- /dev/null
+++ b/WebServer/Response/AuthAdminKeyResponse.cs
@@ -0,0 +1,13 @@
+namespace EggLink.DanhengServer.WebServer.Response
+{
+ public class AuthAdminKeyResponse(int code, string message, AuthAdminKeyData? data) : BaseResponse(code, message, data)
+ {
+ }
+
+ public class AuthAdminKeyData
+ {
+ public string RsaPublicKey { get; set; } = "";
+ public string SessionId { get; set; } = "";
+ public long ExpireTimeStamp { get; set; } = 0;
+ }
+}
diff --git a/WebServer/Response/BaseResponse.cs b/WebServer/Response/BaseResponse.cs
new file mode 100644
index 00000000..69ef3a7b
--- /dev/null
+++ b/WebServer/Response/BaseResponse.cs
@@ -0,0 +1,14 @@
+namespace EggLink.DanhengServer.WebServer.Response
+{
+ public class BaseResponse(int code, string message, T? data)
+ {
+ public int Code { get; set; } = code;
+ public string Message { get; set; } = message;
+
+ public T? Data { get; set; } = data;
+ }
+
+ public class BasicResponse(int code, string message) : BaseResponse