diff --git a/Arrowgene.Ddon.GameServer/Characters/CharacterManager.cs b/Arrowgene.Ddon.GameServer/Characters/CharacterManager.cs index cb3e1c3c8..247655845 100644 --- a/Arrowgene.Ddon.GameServer/Characters/CharacterManager.cs +++ b/Arrowgene.Ddon.GameServer/Characters/CharacterManager.cs @@ -61,7 +61,7 @@ public Character SelectCharacter(uint characterId, DbConnection? connectionIn = character.EpitaphRoadState.UnlockedContent = _Server.Database.GetEpitaphRoadUnlocks(character.CharacterId, connectionIn); - if (_Server.Setting.GameLogicSetting.EnableEpitaphWeeklyRewards.Value) + if (_Server.Setting.GameLogicSetting.EnableEpitaphWeeklyRewards) { character.EpitaphRoadState.WeeklyRewardsClaimed = _Server.Database.GetEpitaphClaimedWeeklyRewards(character.CharacterId, connectionIn); } diff --git a/Arrowgene.Ddon.GameServer/Characters/ClanManager.cs b/Arrowgene.Ddon.GameServer/Characters/ClanManager.cs index 3c9d0a6a1..5b6fd57f0 100644 --- a/Arrowgene.Ddon.GameServer/Characters/ClanManager.cs +++ b/Arrowgene.Ddon.GameServer/Characters/ClanManager.cs @@ -520,7 +520,7 @@ public PacketQueue CompleteClanQuest(Quest quest, GameClient client) { ClanQuestClearCount[characterId][quest.QuestScheduleId] = ClanQuestClearCount[characterId].GetValueOrDefault(quest.QuestScheduleId) + 1; - Server.RpcManager.AnnounceOthers("internal/tracking", RpcInternalCommand.NotifyClanQuestCompletion, new RpcQuestCompletionData() + Server.RpcManager.AnnounceOthers("internal/command", RpcInternalCommand.NotifyClanQuestCompletion, new RpcQuestCompletionData() { CharacterId = characterId, QuestStatus = ClanQuestClearCount[characterId] diff --git a/Arrowgene.Ddon.GameServer/Characters/EpitaphRoadManager.cs b/Arrowgene.Ddon.GameServer/Characters/EpitaphRoadManager.cs index 34c959d00..41bce2482 100644 --- a/Arrowgene.Ddon.GameServer/Characters/EpitaphRoadManager.cs +++ b/Arrowgene.Ddon.GameServer/Characters/EpitaphRoadManager.cs @@ -1290,7 +1290,7 @@ public List RollGatheringLoot(GameClient client, Charact { results.AddRange(RollWeeklyChestReward(dungeonInfo, reward)); - if (_Server.Setting.GameLogicSetting.EnableEpitaphWeeklyRewards.Value) + if (_Server.Setting.GameLogicSetting.EnableEpitaphWeeklyRewards) { character.EpitaphRoadState.WeeklyRewardsClaimed.Add(reward.EpitaphId); _Server.Database.InsertEpitaphWeeklyReward(character.CharacterId, reward.EpitaphId); diff --git a/Arrowgene.Ddon.GameServer/Characters/ExpManager.cs b/Arrowgene.Ddon.GameServer/Characters/ExpManager.cs index 45c3bde9f..b85978659 100644 --- a/Arrowgene.Ddon.GameServer/Characters/ExpManager.cs +++ b/Arrowgene.Ddon.GameServer/Characters/ExpManager.cs @@ -10,7 +10,6 @@ using System; using System.Collections.Generic; using System.Data.Common; -using System.Drawing; using System.Linq; namespace Arrowgene.Ddon.GameServer.Characters @@ -906,13 +905,13 @@ public uint GetScaledPointAmount(RewardSource source, ExpType type, uint amount) switch (type) { case ExpType.ExperiencePoints: - modifier = (source == RewardSource.Enemy) ? _GameSettings.EnemyExpModifier.Value : _GameSettings.QuestExpModifier.Value; + modifier = (source == RewardSource.Enemy) ? _GameSettings.EnemyExpModifier : _GameSettings.QuestExpModifier; break; case ExpType.JobPoints: - modifier = _GameSettings.JpModifier.Value; + modifier = _GameSettings.JpModifier; break; case ExpType.PlayPoints: - modifier = _GameSettings.PpModifier.Value; + modifier = _GameSettings.PpModifier; break; default: modifier = 1.0; diff --git a/Arrowgene.Ddon.GameServer/Characters/RewardManager.cs b/Arrowgene.Ddon.GameServer/Characters/RewardManager.cs index a6a9eea34..b922f3c2c 100644 --- a/Arrowgene.Ddon.GameServer/Characters/RewardManager.cs +++ b/Arrowgene.Ddon.GameServer/Characters/RewardManager.cs @@ -1,10 +1,8 @@ -using Arrowgene.Ddon.Server; using Arrowgene.Ddon.GameServer.Quests; +using Arrowgene.Ddon.Server; +using Arrowgene.Ddon.Shared.Model.Quest; using Arrowgene.Logging; using System.Collections.Generic; -using Arrowgene.Ddon.Shared.Model.Quest; -using Arrowgene.Ddon.Shared.Model; -using Arrowgene.Ddon.Database.Model; using System.Data.Common; namespace Arrowgene.Ddon.GameServer.Characters @@ -24,7 +22,7 @@ public bool AddQuestRewards(GameClient client, Quest quest, DbConnection? connec var rewards = quest.GenerateBoxRewards(); var currentRewards = GetQuestBoxRewards(client, connectionIn); - if (currentRewards.Count >= _Server.Setting.GameLogicSetting.RewardBoxMax.Value) + if (currentRewards.Count >= _Server.Setting.GameLogicSetting.RewardBoxMax) { return false; } diff --git a/Arrowgene.Ddon.GameServer/Characters/WalletManager.cs b/Arrowgene.Ddon.GameServer/Characters/WalletManager.cs index f77e0a996..91e407be5 100644 --- a/Arrowgene.Ddon.GameServer/Characters/WalletManager.cs +++ b/Arrowgene.Ddon.GameServer/Characters/WalletManager.cs @@ -107,16 +107,16 @@ public uint GetScaledWalletAmount(WalletType type, uint amount) switch (type) { case WalletType.Gold: - modifier = Server.Setting.GameLogicSetting.GoldModifier.Value; + modifier = Server.Setting.GameLogicSetting.GoldModifier; break; case WalletType.RiftPoints: - modifier = Server.Setting.GameLogicSetting.RiftModifier.Value; + modifier = Server.Setting.GameLogicSetting.RiftModifier; break; case WalletType.BloodOrbs: - modifier = Server.Setting.GameLogicSetting.BoModifier.Value; + modifier = Server.Setting.GameLogicSetting.BoModifier; break; case WalletType.HighOrbs: - modifier = Server.Setting.GameLogicSetting.HoModifier.Value; + modifier = Server.Setting.GameLogicSetting.HoModifier; break; default: modifier = 1.0; diff --git a/Arrowgene.Ddon.GameServer/GameServerSetting.cs b/Arrowgene.Ddon.GameServer/GameServerSetting.cs index 2839e7727..b1fba56c1 100644 --- a/Arrowgene.Ddon.GameServer/GameServerSetting.cs +++ b/Arrowgene.Ddon.GameServer/GameServerSetting.cs @@ -1,4 +1,4 @@ -using System.Runtime.Serialization; +using System.Runtime.Serialization; using Arrowgene.Ddon.Server; namespace Arrowgene.Ddon.GameServer @@ -11,13 +11,7 @@ public class GameServerSetting public GameServerSetting() { - ServerSetting = new ServerSetting(); - ServerSetting.Id = 10; - ServerSetting.Name = "Game"; - ServerSetting.ServerPort = 52000; - ServerSetting.ServerSocketSettings.Identity = "Game"; - - GameLogicSetting = new GameLogicSetting(); + SetDefaultValues(); } public GameServerSetting(GameServerSetting setting) @@ -41,5 +35,22 @@ void OnDeserialized(StreamingContext context) GameLogicSetting ??= new GameLogicSetting(); } + + [OnDeserializing] + void OnDeserializing(StreamingContext context) + { + SetDefaultValues(); + } + + void SetDefaultValues() + { + ServerSetting = new ServerSetting(); + ServerSetting.Id = 10; + ServerSetting.Name = "Game"; + ServerSetting.ServerPort = 52000; + ServerSetting.ServerSocketSettings.Identity = "Game"; + + GameLogicSetting = new GameLogicSetting(); + } } } diff --git a/Arrowgene.Ddon.GameServer/Handler/InstanceEnemyKillHandler.cs b/Arrowgene.Ddon.GameServer/Handler/InstanceEnemyKillHandler.cs index cb575a332..e891245d0 100644 --- a/Arrowgene.Ddon.GameServer/Handler/InstanceEnemyKillHandler.cs +++ b/Arrowgene.Ddon.GameServer/Handler/InstanceEnemyKillHandler.cs @@ -209,7 +209,7 @@ public override S2CInstanceEnemyKillRes Handle(GameClient client, C2SInstanceEne if (enemyKilled.BloodOrbs > 0) { // Drop BO - uint gainedBo = (uint) (enemyKilled.BloodOrbs * _gameServer.Setting.GameLogicSetting.BoModifier.Value); + uint gainedBo = (uint) (enemyKilled.BloodOrbs * _gameServer.Setting.GameLogicSetting.BoModifier); uint bonusBo = (uint) (gainedBo * _gameServer.GpCourseManager.EnemyBloodOrbBonus()); CDataUpdateWalletPoint boUpdateWalletPoint = _gameServer.WalletManager.AddToWallet(memberClient.Character, WalletType.BloodOrbs, gainedBo + bonusBo, bonusBo, connectionIn: connectionIn); updateCharacterItemNtc.UpdateWalletList.Add(boUpdateWalletPoint); @@ -218,7 +218,7 @@ public override S2CInstanceEnemyKillRes Handle(GameClient client, C2SInstanceEne if (enemyKilled.HighOrbs > 0) { // Drop HO - uint gainedHo = (uint)(enemyKilled.HighOrbs * _gameServer.Setting.GameLogicSetting.HoModifier.Value); + uint gainedHo = (uint)(enemyKilled.HighOrbs * _gameServer.Setting.GameLogicSetting.HoModifier); CDataUpdateWalletPoint hoUpdateWalletPoint = _gameServer.WalletManager.AddToWallet(memberClient.Character, WalletType.HighOrbs, gainedHo, connectionIn: connectionIn); updateCharacterItemNtc.UpdateWalletList.Add(hoUpdateWalletPoint); } diff --git a/Arrowgene.Ddon.GameServer/Handler/QuestGetCycleContentsStateListHandler.cs b/Arrowgene.Ddon.GameServer/Handler/QuestGetCycleContentsStateListHandler.cs index fe946366c..45a3c99a4 100644 --- a/Arrowgene.Ddon.GameServer/Handler/QuestGetCycleContentsStateListHandler.cs +++ b/Arrowgene.Ddon.GameServer/Handler/QuestGetCycleContentsStateListHandler.cs @@ -1,6 +1,5 @@ using Arrowgene.Ddon.GameServer.Characters; using Arrowgene.Ddon.GameServer.Dump; -using Arrowgene.Ddon.GameServer.Quests; using Arrowgene.Ddon.Server; using Arrowgene.Ddon.Shared.Entity; using Arrowgene.Ddon.Shared.Entity.PacketStructure; @@ -36,8 +35,8 @@ public override S2CQuestGetCycleContentsStateListRes Handle(GameClient client, C ntc.WorldManageQuestOrderList = pcap.WorldManageQuestOrderList; // Recover paths + change vocation ntc.QuestDefine = pcap.QuestDefine; // Recover quest log data to be able to accept quests - ntc.QuestDefine.OrderMaxNum = Server.Setting.GameLogicSetting.QuestOrderMax.Value; - ntc.QuestDefine.RewardBoxMaxNum = Server.Setting.GameLogicSetting.RewardBoxMax.Value; + ntc.QuestDefine.OrderMaxNum = Server.Setting.GameLogicSetting.QuestOrderMax; + ntc.QuestDefine.RewardBoxMaxNum = Server.Setting.GameLogicSetting.RewardBoxMax; // pcap.MainQuestIdList; (this will add back all missing functionality which depends on complete MSQ) var completedMsq = client.Character.CompletedQuests.Values.Where(x => x.QuestType == QuestType.Main); diff --git a/Arrowgene.Ddon.GameServer/RpcManager.cs b/Arrowgene.Ddon.GameServer/RpcManager.cs index 0e47f642a..82ff7a66e 100644 --- a/Arrowgene.Ddon.GameServer/RpcManager.cs +++ b/Arrowgene.Ddon.GameServer/RpcManager.cs @@ -9,13 +9,10 @@ using Arrowgene.Logging; using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Net.Http; using System.Net.Http.Json; -using System.Security.Claims; using System.Text.Json; -using System.Text.Json.Serialization; using System.Threading.Tasks; namespace Arrowgene.Ddon.GameServer @@ -60,52 +57,6 @@ public bool Update(DateTime newTimestamp, List characterData) private readonly Dictionary CharacterTrackingMap; - public class RpcWrappedObject - { - public RpcInternalCommand Command { get; set; } - public ushort Origin { get; set; } - public object Data { get; set; } - public DateTime Timestamp { get; set; } - public RpcWrappedObject() - { - Timestamp = DateTime.UtcNow; - } - } - - public class RpcUnwrappedObject - { - public RpcInternalCommand Command { get; set; } - public ushort Origin { get; set; } - public DateTime Timestamp { get; set; } - - [JsonConverter(typeof(DataJsonConverter))] - public string Data { get; set; } - public T GetData() - { - return JsonSerializer.Deserialize(Data); - } - - // Hack to deserialize nested objects. - internal class DataJsonConverter : JsonConverter - { - public override string Read( - ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - using (var jsonDoc = JsonDocument.ParseValue(ref reader)) - { - return jsonDoc.RootElement.GetRawText(); - } - } - - public override void Write( - Utf8JsonWriter writer, string value, JsonSerializerOptions options) - { - throw new NotImplementedException(); - } - } - } - - public RpcManager(DdonGameServer server) { Server = server; @@ -296,7 +247,7 @@ public void AnnouncePlayerList(Character exception = null) rpcCharacterDatas.Add(new(character)); } Logger.Info($"Announcing player list for channel {Server.Id} with {rpcCharacterDatas.Count} players over RPC."); - AnnounceOthers("internal/tracking", RpcInternalCommand.NotifyPlayerList, rpcCharacterDatas); + AnnounceOthers("internal/command", RpcInternalCommand.NotifyPlayerList, rpcCharacterDatas); CharacterTrackingMap[(ushort) Server.Id].Update(DateTime.Now, rpcCharacterDatas); } @@ -419,10 +370,5 @@ public void AnnounceClanPacket(uint clanId, T packet, uint characterId = 0) AnnounceClan(clanId, "internal/packet", RpcInternalCommand.AnnouncePacketClan, data); } } - - public void AnnounceEpitaphWeeklyReset() - { - AnnounceAll("internal/packet", RpcInternalCommand.EpitaphRoadWeeklyReset, null); - } } } diff --git a/Arrowgene.Ddon.GameServer/Tasks/EpitaphSchedulerTask.cs b/Arrowgene.Ddon.GameServer/Tasks/EpitaphSchedulerTask.cs index ff835cb9f..a47fd3dc1 100644 --- a/Arrowgene.Ddon.GameServer/Tasks/EpitaphSchedulerTask.cs +++ b/Arrowgene.Ddon.GameServer/Tasks/EpitaphSchedulerTask.cs @@ -1,5 +1,4 @@ using Arrowgene.Ddon.Server; -using Arrowgene.Ddon.Shared.Model; using Arrowgene.Ddon.Shared.Model.Rpc; using Arrowgene.Ddon.Shared.Model.Scheduler; using Arrowgene.Logging; @@ -18,15 +17,14 @@ public EpitaphSchedulerTask(DayOfWeek day, uint hour, uint minute) : base(TaskTy public override bool IsEnabled(DdonGameServer server) { - return server.Setting.GameLogicSetting.EnableEpitaphWeeklyRewards.Value; + return server.Setting.GameLogicSetting.EnableEpitaphWeeklyRewards; } public override void RunTask(DdonGameServer server) { Logger.Info("Performing weekly epitaph reset"); server.Database.DeleteWeeklyEpitaphClaimedRewards(); - - server.RpcManager.AnnounceEpitaphWeeklyReset(); + server.RpcManager.AnnounceAll("internal/packet", RpcInternalCommand.EpitaphRoadWeeklyReset, null); } } } diff --git a/Arrowgene.Ddon.LoginServer/Handler/ClientLoginHandler.cs b/Arrowgene.Ddon.LoginServer/Handler/ClientLoginHandler.cs index 2e3b18d8f..09b71cb44 100644 --- a/Arrowgene.Ddon.LoginServer/Handler/ClientLoginHandler.cs +++ b/Arrowgene.Ddon.LoginServer/Handler/ClientLoginHandler.cs @@ -1,11 +1,16 @@ -using System; -using System.Collections.Generic; using Arrowgene.Ddon.Database.Model; using Arrowgene.Ddon.Server; using Arrowgene.Ddon.Shared.Entity.PacketStructure; using Arrowgene.Ddon.Shared.Model; +using Arrowgene.Ddon.Shared.Model.Rpc; using Arrowgene.Ddon.Shared.Network; using Arrowgene.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text.Json; +using System.Threading; namespace Arrowgene.Ddon.LoginServer.Handler { @@ -17,6 +22,9 @@ public class ClientLoginHandler : LoginStructurePacketHandler private readonly object _tokensInFLightLock; private readonly HashSet _tokensInFlight; + private readonly HttpClient _httpClient = new HttpClient(); + private bool _httpReady = false; + public ClientLoginHandler(DdonLoginServer server) : base(server) { _setting = server.Setting; @@ -101,14 +109,32 @@ public override void Handle(LoginClient client, StructurePacket pac } List connections = Database.SelectConnectionsByAccountId(account.Id); - if (connections.Count > 0) + + if (_setting.KickOnMultipleLogin) + { + for (uint tryCount = 0; tryCount < _setting.KickOnMultipleLoginTries; tryCount++) + { + if (connections.Any()) + { + connections.ForEach(x => RequestKick(x)); + Thread.Sleep(_setting.KickOnMultipleLoginTimer); + connections = Database.SelectConnectionsByAccountId(account.Id); + } + else + { + break; + } + } + } + + if (connections.Any()) { - Logger.Error(client, $"Already logged in"); - res.Error = (uint) ErrorCode.ERROR_CODE_AUTH_MULTIPLE_LOGIN; + Logger.Error(client, $"Already logged in."); + res.Error = (uint)ErrorCode.ERROR_CODE_AUTH_MULTIPLE_LOGIN; client.Send(res); return; } - + // Order Important, // account need to be only assigned after // verification that no connection exists, and before @@ -172,5 +198,45 @@ private bool LockToken(string token) return true; } } + + private void RequestKick(Connection connection) + { + // Timing issues with loading files vs server process startup. + if (!_httpReady) + { + lock(_httpClient) + { + ServerInfo serverInfo = Server.AssetRepository.ServerList.Find(x => x.LoginId == Server.Id); + if (serverInfo is null) + { + Logger.Error($"Login server with ID {Server.Id} was not found in the ServerList asset."); + return; + } + + // The login server auths as though it was the game server. + _httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Internal", $"{serverInfo.Id}:{serverInfo.RpcAuthToken}"); + _httpReady = true; + } + } + + if (connection.Type == ConnectionType.LoginServer) + { + // Can't talk to the login server, but there's usually not a stuck connection here. + return; + } + + var channel = Server.AssetRepository.ServerList.Find(x => x.Id == connection.ServerId); + var route = $"http://{channel.Addr}:{channel.RpcPort}/rpc/internal/command"; + + var wrappedObject = new RpcWrappedObject() + { + Command = RpcInternalCommand.KickInternal, + Origin = (ushort)Server.Id, + Data = connection.AccountId + }; + + var json = JsonSerializer.Serialize(wrappedObject); + _ = _httpClient.PostAsync(route, new StringContent(json)); + } } } diff --git a/Arrowgene.Ddon.Rpc.Web/Route/Internal/TrackingRoute.cs b/Arrowgene.Ddon.Rpc.Web/Route/Internal/CommandRoute.cs similarity index 58% rename from Arrowgene.Ddon.Rpc.Web/Route/Internal/TrackingRoute.cs rename to Arrowgene.Ddon.Rpc.Web/Route/Internal/CommandRoute.cs index 55adc062d..b73974954 100644 --- a/Arrowgene.Ddon.Rpc.Web/Route/Internal/TrackingRoute.cs +++ b/Arrowgene.Ddon.Rpc.Web/Route/Internal/CommandRoute.cs @@ -5,21 +5,20 @@ using Arrowgene.WebServer; using System.Collections.Generic; using System.Threading.Tasks; -using static Arrowgene.Ddon.GameServer.RpcManager; namespace Arrowgene.Ddon.Rpc.Web.Route.Internal { - public class TrackingRoute : RpcRouteTemplate + public class CommandRoute : RpcRouteTemplate { - public class InternalTrackingCommand : RpcBodyCommand + public class InternalCommand : RpcBodyCommand { - private static readonly ILogger Logger = LogProvider.Logger(typeof(InternalTrackingCommand)); + private static readonly ILogger Logger = LogProvider.Logger(typeof(InternalCommand)); - public InternalTrackingCommand(RpcUnwrappedObject entry) : base(entry) + public InternalCommand(RpcUnwrappedObject entry) : base(entry) { } - public override string Name => "InternalTrackingCommand"; + public override string Name => "InternalCommand"; public override RpcCommandResult Execute(DdonGameServer gameServer) { @@ -43,21 +42,39 @@ public override RpcCommandResult Execute(DdonGameServer gameServer) Message = $"NotifyClanQuestCompletion for CharacterId {data.CharacterId}" }; } + case RpcInternalCommand.EpitaphRoadWeeklyReset: + { + gameServer.EpitaphRoadManager.PerformWeeklyReset(); + return new RpcCommandResult(this, true); + } + case RpcInternalCommand.KickInternal: + { + int target = _entry.GetData(); + foreach (var client in gameServer.ClientLookup.GetAll()) + { + if (client.Account.Id == target) + { + client.Close(); + } + } + gameServer.Database.DeleteConnection(gameServer.Id, target); + return new RpcCommandResult(this, true); + } default: return new RpcCommandResult(this, false); } } } - public TrackingRoute(IRpcExecuter executer) : base(executer) + public CommandRoute(IRpcExecuter executer) : base(executer) { } - public override string Route => "/rpc/internal/tracking"; + public override string Route => "/rpc/internal/command"; public async override Task Post(WebRequest request) { - return await HandleBody(request); + return await HandleBody(request); } } } diff --git a/Arrowgene.Ddon.Rpc.Web/Route/Internal/PacketRoute.cs b/Arrowgene.Ddon.Rpc.Web/Route/Internal/PacketRoute.cs index 89d0d44b7..4e8f2b351 100644 --- a/Arrowgene.Ddon.Rpc.Web/Route/Internal/PacketRoute.cs +++ b/Arrowgene.Ddon.Rpc.Web/Route/Internal/PacketRoute.cs @@ -1,17 +1,14 @@ using Arrowgene.Ddon.GameServer; -using Arrowgene.Ddon.GameServer.Characters; using Arrowgene.Ddon.Rpc.Command; using Arrowgene.Ddon.Shared.Entity.PacketStructure; using Arrowgene.Ddon.Shared.Entity.Structure; using Arrowgene.Ddon.Shared.Model; using Arrowgene.Ddon.Shared.Model.Clan; -using Arrowgene.Ddon.Shared.Model.Quest; using Arrowgene.Ddon.Shared.Model.Rpc; using Arrowgene.Ddon.Shared.Network; using Arrowgene.Logging; using Arrowgene.WebServer; using System; -using System.Linq; using System.Threading.Tasks; using static Arrowgene.Ddon.GameServer.RpcManager; @@ -168,9 +165,7 @@ public override RpcCommandResult Execute(DdonGameServer gameServer) Message = $"AnnouncePacketClan Ch.{_entry.Origin} ClanID {data.ClanId} -> {packet.Id}" }; } - case RpcInternalCommand.EpitaphRoadWeeklyReset: - gameServer.EpitaphRoadManager.PerformWeeklyReset(); - return new RpcCommandResult(this, true); + default: return new RpcCommandResult(this, false); } diff --git a/Arrowgene.Ddon.Rpc.Web/RpcWebServer.cs b/Arrowgene.Ddon.Rpc.Web/RpcWebServer.cs index 954b86fd5..2be935da6 100644 --- a/Arrowgene.Ddon.Rpc.Web/RpcWebServer.cs +++ b/Arrowgene.Ddon.Rpc.Web/RpcWebServer.cs @@ -37,7 +37,7 @@ public void Init() #region Internal RPC InternalMiddleware internalMiddleware = new InternalMiddleware(_gameServer); - Route.Internal.TrackingRoute trackingRoute = new(this); + Route.Internal.CommandRoute trackingRoute = new(this); internalMiddleware.Require(trackingRoute.Route); _webServer.AddRoute(trackingRoute); diff --git a/Arrowgene.Ddon.Server/GameLogicSetting.cs b/Arrowgene.Ddon.Server/GameLogicSetting.cs index 5b0ec0f88..3b67942ab 100644 --- a/Arrowgene.Ddon.Server/GameLogicSetting.cs +++ b/Arrowgene.Ddon.Server/GameLogicSetting.cs @@ -2,29 +2,9 @@ using System; using System.Collections.Generic; using System.Runtime.Serialization; -using YamlDotNet.Serialization; namespace Arrowgene.Ddon.Server { - [DataContract] - public class DefaultDataMember - { - private T _DefaultValue; - private T? _Value; - - [DataMember] - public T Value { - get => _Value ?? _DefaultValue; - set => _Value = Value; - } - - public DefaultDataMember(T defaultValue) - { - _DefaultValue = defaultValue; - } - } - - [DataContract] public class GameLogicSetting { @@ -189,58 +169,58 @@ public class GameLogicSetting /// /// Global modifier for enemy exp calculations to scale up or down. /// - [DataMember(Order = 27)] public double? EnemyExpModifier { get; set; } = 1.0; + [DataMember(Order = 27)] public double EnemyExpModifier { get; set; } /// /// Global modifier for quest exp calculations to scale up or down. /// - [DataMember(Order = 28)] public double? QuestExpModifier { get; set; } = 1.0; + [DataMember(Order = 28)] public double QuestExpModifier { get; set; } /// /// Global modifier for pp calculations to scale up or down. /// - [DataMember(Order = 29)] public double? PpModifier { get; set; } = 1.0; + [DataMember(Order = 29)] public double PpModifier { get; set; } /// /// Global modifier for Gold calculations to scale up or down. /// - [DataMember(Order = 30)] public double? GoldModifier { get; set; } = 1.0; + [DataMember(Order = 30)] public double GoldModifier { get; set; } /// /// Global modifier for Rift calculations to scale up or down. /// - [DataMember(Order = 31)] public double? RiftModifier { get; set; } = 1.0; + [DataMember(Order = 31)] public double RiftModifier { get; set; } /// /// Global modifier for BO calculations to scale up or down. /// - [DataMember(Order = 32)] public double? BoModifier { get; set; } = 1.0; + [DataMember(Order = 32)] public double BoModifier { get; set; } /// /// Global modifier for HO calculations to scale up or down. /// - [DataMember(Order = 33)] public double? HoModifier { get; set; } = 1.0; + [DataMember(Order = 33)] public double HoModifier { get; set; } /// /// Global modifier for JP calculations to scale up or down. /// - [DataMember(Order = 34)] public double? JpModifier { get; set; } = 1.0; + [DataMember(Order = 34)] public double JpModifier { get; set; } /// /// Configures the maximum amount of reward box slots. /// - [DataMember(Order = 35)] public byte? RewardBoxMax { get; set; } = 100; + [DataMember(Order = 35)] public byte RewardBoxMax { get; set; } /// /// Configures the maximum amount of quests that can be ordered at one time. /// - [DataMember(Order = 36)] public byte? QuestOrderMax { get; set; } = 20; + [DataMember(Order = 36)] public byte QuestOrderMax { get; set; } /// /// Configures if epitaph rewards are limited once per weekly reset. /// - [DataMember(Order = 37)] public bool? EnableEpitaphWeeklyRewards { get; set; } = true; + [DataMember(Order = 37)] public bool EnableEpitaphWeeklyRewards { get; set; } /// /// Enables main pawns in party to gain EXP and JP from quests @@ -286,6 +266,11 @@ public class GameLogicSetting [DataMember(Order = 200)] public string UrlCompanionImage { get; set; } public GameLogicSetting() + { + SetDefaultValues(); + } + + void SetDefaultValues() { LaternBurnTimeInSeconds = 1500; AdditionalProductionSpeedFactor = 1.0; @@ -372,6 +357,12 @@ public GameLogicSetting() UrlCompanionImage = $"{urlDomain}/"; } + [OnDeserializing] + void OnDeserializing(StreamingContext context) + { + SetDefaultValues(); + } + public GameLogicSetting(GameLogicSetting setting) { LaternBurnTimeInSeconds = setting.LaternBurnTimeInSeconds; @@ -444,44 +435,6 @@ public GameLogicSetting(GameLogicSetting setting) [OnDeserialized] void OnDeserialized(StreamingContext context) { - // Initialize reference types so tests work properly. - AdjustPartyEnemyExpTiers ??= new(); - AdjustTargetLvEnemyExpTiers ??= new(); - WeatherStatistics ??= new(); - WalletLimits ??= new(); - UrlManual ??= string.Empty; - UrlShopDetail ??= string.Empty; - UrlShopCounterA ??= string.Empty; - UrlShopAttention ??= string.Empty; - UrlShopStoneLimit ??= string.Empty; - UrlShopCounterB ??= string.Empty; - UrlChargeCallback ??= string.Empty; - UrlChargeA ??= string.Empty; - UrlSample9 ??= string.Empty; - UrlSample10 ??= string.Empty; - UrlCampaignBanner ??= string.Empty; - UrlSupportIndex ??= string.Empty; - UrlPhotoupAuthorize ??= string.Empty; - UrlApiA ??= string.Empty; - UrlApiB ??= string.Empty; - UrlIndex ??= string.Empty; - UrlCampaign ??= string.Empty; - UrlChargeB ??= string.Empty; - UrlCompanionImage ??= string.Empty; - - EnableEpitaphWeeklyRewards ??= true; - - EnemyExpModifier ??= 1; - QuestExpModifier ??= 1; - PpModifier ??= 1; - GoldModifier ??= 1; - RiftModifier ??= 1; - BoModifier ??= 1; - HoModifier ??= 1; - JpModifier ??= 1; - RewardBoxMax ??= 100; - QuestOrderMax ??= 20; - if (RookiesRingBonus < 0) { RookiesRingBonus = 1.0; diff --git a/Arrowgene.Ddon.Server/LoginServerSetting.cs b/Arrowgene.Ddon.Server/LoginServerSetting.cs index 2b57cd280..27fd0e632 100644 --- a/Arrowgene.Ddon.Server/LoginServerSetting.cs +++ b/Arrowgene.Ddon.Server/LoginServerSetting.cs @@ -8,8 +8,32 @@ public class LoginServerSetting [DataMember(Order = 1)] public ServerSetting ServerSetting { get; set; } [DataMember(Order = 90)] public bool AccountRequired { get; set; } [DataMember(Order = 105)] public uint NoOperationTimeOutTime { get; set; } - + [DataMember(Order = 110)] public bool KickOnMultipleLogin { get; set; } + [DataMember(Order = 111)] public int KickOnMultipleLoginTries { get; set; } + [DataMember(Order = 112)] public int KickOnMultipleLoginTimer { get; set; } + public LoginServerSetting() + { + SetDefaultValues(); + } + + public LoginServerSetting(LoginServerSetting setting) + { + ServerSetting = new ServerSetting(setting.ServerSetting); + AccountRequired = setting.AccountRequired; + NoOperationTimeOutTime = setting.NoOperationTimeOutTime; + KickOnMultipleLogin = setting.KickOnMultipleLogin; + KickOnMultipleLoginTries = setting.KickOnMultipleLoginTries; + KickOnMultipleLoginTimer = setting.KickOnMultipleLoginTimer; + } + + [OnDeserializing] + void OnDeserializing(StreamingContext context) + { + SetDefaultValues(); + } + + void SetDefaultValues() { ServerSetting = new ServerSetting(); ServerSetting.Id = 1; @@ -19,13 +43,9 @@ public LoginServerSetting() AccountRequired = false; NoOperationTimeOutTime = 14400; - } - - public LoginServerSetting(LoginServerSetting setting) - { - ServerSetting = new ServerSetting(setting.ServerSetting); - AccountRequired = setting.AccountRequired; - NoOperationTimeOutTime = setting.NoOperationTimeOutTime; + KickOnMultipleLogin = false; + KickOnMultipleLoginTries = 3; + KickOnMultipleLoginTimer = 5000; } } } diff --git a/Arrowgene.Ddon.Shared/Csv/GameServerListInfoCsv.cs b/Arrowgene.Ddon.Shared/Csv/GameServerListInfoCsv.cs index 14c6cfb6b..48c63295a 100644 --- a/Arrowgene.Ddon.Shared/Csv/GameServerListInfoCsv.cs +++ b/Arrowgene.Ddon.Shared/Csv/GameServerListInfoCsv.cs @@ -5,7 +5,7 @@ namespace Arrowgene.Ddon.Shared.Csv; public class GameServerListInfoCsv : CsvReaderWriter { - protected override int NumExpectedItems => 9; + protected override int NumExpectedItems => 10; protected override ServerInfo CreateInstance(string[] properties) { if (!ushort.TryParse(properties[0], out ushort id)) return null; @@ -17,6 +17,7 @@ protected override ServerInfo CreateInstance(string[] properties) if (!bool.TryParse(properties[6], out bool isHide)) return null; if (!ushort.TryParse(properties[7], out ushort rpcPort)) return null; string authToken = properties[8]; + if (!ushort.TryParse(properties[9], out ushort loginId)) return null; return new ServerInfo() { @@ -30,6 +31,7 @@ protected override ServerInfo CreateInstance(string[] properties) IsHide = isHide, RpcPort = rpcPort, RpcAuthToken = authToken, + LoginId = loginId, }; } } diff --git a/Arrowgene.Ddon.Shared/Files/Assets/GameServerList.csv b/Arrowgene.Ddon.Shared/Files/Assets/GameServerList.csv index 364d35c87..4e4590821 100644 --- a/Arrowgene.Ddon.Shared/Files/Assets/GameServerList.csv +++ b/Arrowgene.Ddon.Shared/Files/Assets/GameServerList.csv @@ -1,2 +1,2 @@ -#Id,Name,Brief,MaxLoginNum,IpAddress,Port,IsHide,RpcPort,RpcAuth -10,Local Host,Brief,1000,127.0.0.1,52000,false,52099,AuthToken \ No newline at end of file +#Id,Name,Brief,MaxLoginNum,IpAddress,Port,IsHide,RpcPort,RpcAuth,LoginId +10,Local Host,Brief,1000,127.0.0.1,52000,false,52099,AuthToken,1 \ No newline at end of file diff --git a/Arrowgene.Ddon.Shared/Model/Rpc/RpcInternalCommand.cs b/Arrowgene.Ddon.Shared/Model/Rpc/RpcInternalCommand.cs index b4a8a1359..db43f5a0e 100644 --- a/Arrowgene.Ddon.Shared/Model/Rpc/RpcInternalCommand.cs +++ b/Arrowgene.Ddon.Shared/Model/Rpc/RpcInternalCommand.cs @@ -2,15 +2,18 @@ namespace Arrowgene.Ddon.Shared.Model.Rpc { public enum RpcInternalCommand { + //CommandRoute NotifyPlayerList, // List NotifyClanQuestCompletion, //RpcQuestCompletionData + EpitaphRoadWeeklyReset, // null + KickInternal, // int + //InternalChatRoute SendTellMessage, // RpcChatData SendClanMessage, // RpcChatData + //PacketRoute AnnouncePacketAll, // RpcPacketData AnnouncePacketClan, // RpcPacketData - - EpitaphRoadWeeklyReset } } diff --git a/Arrowgene.Ddon.Shared/Model/Rpc/RpcUnwrappedObject.cs b/Arrowgene.Ddon.Shared/Model/Rpc/RpcUnwrappedObject.cs new file mode 100644 index 000000000..b3cbafaf9 --- /dev/null +++ b/Arrowgene.Ddon.Shared/Model/Rpc/RpcUnwrappedObject.cs @@ -0,0 +1,39 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Arrowgene.Ddon.Shared.Model.Rpc +{ + public class RpcUnwrappedObject + { + public RpcInternalCommand Command { get; set; } + public ushort Origin { get; set; } + public DateTime Timestamp { get; set; } + + [JsonConverter(typeof(DataJsonConverter))] + public string Data { get; set; } + public T GetData() + { + return JsonSerializer.Deserialize(Data); + } + + // Hack to deserialize nested objects. + internal class DataJsonConverter : JsonConverter + { + public override string Read( + ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + using (var jsonDoc = JsonDocument.ParseValue(ref reader)) + { + return jsonDoc.RootElement.GetRawText(); + } + } + + public override void Write( + Utf8JsonWriter writer, string value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + } + } +} diff --git a/Arrowgene.Ddon.Shared/Model/Rpc/RpcWrappedObject.cs b/Arrowgene.Ddon.Shared/Model/Rpc/RpcWrappedObject.cs new file mode 100644 index 000000000..3fd1b0d6b --- /dev/null +++ b/Arrowgene.Ddon.Shared/Model/Rpc/RpcWrappedObject.cs @@ -0,0 +1,16 @@ +using System; + +namespace Arrowgene.Ddon.Shared.Model.Rpc +{ + public class RpcWrappedObject + { + public RpcInternalCommand Command { get; set; } + public ushort Origin { get; set; } + public object Data { get; set; } + public DateTime Timestamp { get; set; } + public RpcWrappedObject() + { + Timestamp = DateTime.UtcNow; + } + } +} diff --git a/Arrowgene.Ddon.Shared/Model/ServerInfo.cs b/Arrowgene.Ddon.Shared/Model/ServerInfo.cs index 973374ff3..973fb1d74 100644 --- a/Arrowgene.Ddon.Shared/Model/ServerInfo.cs +++ b/Arrowgene.Ddon.Shared/Model/ServerInfo.cs @@ -21,6 +21,7 @@ public ServerInfo() public bool IsHide { get; set; } public ushort RpcPort { get; set; } public string RpcAuthToken { get; set; } + public ushort LoginId { get; set; } public CDataGameServerListInfo ToCDataGameServerListInfo() {