From 3c5c5d5e1bfd558f2274778c2bc15d80dcf4ba2c Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Fri, 20 Feb 2026 16:58:18 -0600 Subject: [PATCH 01/26] Add Constants WIP --- .../Storage/Metadata/ServerTableMetadataStorage.cs | 3 +++ Maple2.File.Ingest/Mapper/ServerTableMapper.cs | 13 +++++++++++++ Maple2.Model/Common/ServerTableNames.cs | 1 + .../Metadata/ServerTable/ConstantsTable.cs | 14 ++++++++++++++ Maple2.Model/Metadata/ServerTableMetadata.cs | 1 + 5 files changed, 32 insertions(+) create mode 100644 Maple2.Model/Metadata/ServerTable/ConstantsTable.cs diff --git a/Maple2.Database/Storage/Metadata/ServerTableMetadataStorage.cs b/Maple2.Database/Storage/Metadata/ServerTableMetadataStorage.cs index 9a3c1d591..187856d3b 100644 --- a/Maple2.Database/Storage/Metadata/ServerTableMetadataStorage.cs +++ b/Maple2.Database/Storage/Metadata/ServerTableMetadataStorage.cs @@ -29,6 +29,7 @@ public class ServerTableMetadataStorage { private readonly Lazy combineSpawnTable; private readonly Lazy enchantOptionTable; private readonly Lazy unlimitedEnchantOptionTable; + private readonly Lazy constantsTable; public InstanceFieldTable InstanceFieldTable => instanceFieldTable.Value; public ScriptConditionTable ScriptConditionTable => scriptConditionTable.Value; @@ -53,6 +54,7 @@ public class ServerTableMetadataStorage { public CombineSpawnTable CombineSpawnTable => combineSpawnTable.Value; public EnchantOptionTable EnchantOptionTable => enchantOptionTable.Value; public UnlimitedEnchantOptionTable UnlimitedEnchantOptionTable => unlimitedEnchantOptionTable.Value; + public ConstantsTable ConstantsTable => constantsTable.Value; public ServerTableMetadataStorage(MetadataContext context) { instanceFieldTable = Retrieve(context, ServerTableNames.INSTANCE_FIELD); @@ -78,6 +80,7 @@ public ServerTableMetadataStorage(MetadataContext context) { combineSpawnTable = Retrieve(context, ServerTableNames.COMBINE_SPAWN); enchantOptionTable = Retrieve(context, ServerTableNames.ENCHANT_OPTION); unlimitedEnchantOptionTable = Retrieve(context, ServerTableNames.UNLIMITED_ENCHANT_OPTION); + constantsTable = Retrieve(context, ServerTableNames.CONSTANTS); } public IEnumerable GetGameEvents() { diff --git a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs index 0a8043c75..e34ba9d51 100644 --- a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs +++ b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs @@ -5,6 +5,7 @@ using Maple2.File.IO; using Maple2.File.Parser; using Maple2.File.Parser.Enum; +using Maple2.File.Parser.Xml.Table; using Maple2.File.Parser.Xml.Table.Server; using Maple2.Model; using Maple2.Model.Common; @@ -128,6 +129,10 @@ protected override IEnumerable Map() { Name = ServerTableNames.UNLIMITED_ENCHANT_OPTION, Table = ParseUnlimitedEnchantOption(), }; + yield return new ServerTableMetadata { + Name = ServerTableNames.CONSTANTS, + Table = ParseConstants(), + }; } @@ -2107,4 +2112,12 @@ void AddSpecial(Dictionary values, Dictionary(); + foreach ((string key, Parser.Xml.Table.Constants.Key constants) in parser.ParseConstants()) { + results.Add(key, new Model.Metadata.Constants(constants.key, constants.value)); + } + return new ConstantsTable(results); + } } diff --git a/Maple2.Model/Common/ServerTableNames.cs b/Maple2.Model/Common/ServerTableNames.cs index 7a328840f..0761b6ea1 100644 --- a/Maple2.Model/Common/ServerTableNames.cs +++ b/Maple2.Model/Common/ServerTableNames.cs @@ -24,4 +24,5 @@ public static class ServerTableNames { public const string COMBINE_SPAWN = "combineSpawn*.xml"; public const string ENCHANT_OPTION = "enchantOption.xml"; public const string UNLIMITED_ENCHANT_OPTION = "unlimitedEnchantOption.xml"; + public const string CONSTANTS = "constants.xml"; } diff --git a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs new file mode 100644 index 000000000..ae2b913b7 --- /dev/null +++ b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Maple2.Model.Metadata; + +public record ConstantsTable(IReadOnlyDictionary Constants) : ServerTable; + +public record Constants ( + string Key, + string Value + ); diff --git a/Maple2.Model/Metadata/ServerTableMetadata.cs b/Maple2.Model/Metadata/ServerTableMetadata.cs index 097a0b79b..484a6715d 100644 --- a/Maple2.Model/Metadata/ServerTableMetadata.cs +++ b/Maple2.Model/Metadata/ServerTableMetadata.cs @@ -47,4 +47,5 @@ public override int GetHashCode() { [JsonDerivedType(typeof(CombineSpawnTable), typeDiscriminator: "combineSpawn")] [JsonDerivedType(typeof(EnchantOptionTable), typeDiscriminator: "enchantOption")] [JsonDerivedType(typeof(UnlimitedEnchantOptionTable), typeDiscriminator: "unlimitedEnchantOption")] +[JsonDerivedType(typeof(ConstantsTable), typeDiscriminator: "constants")] public abstract record ServerTable; From 55c8d2ad3b06d4181a8c4ff392b651b0638d70e1 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Sun, 22 Feb 2026 21:31:45 -0600 Subject: [PATCH 02/26] Organize and clean-up old constants values WIP. Start using new server constants that are processed during file ingest WIP. --- .../Mapper/ServerTableMapper.cs | 21 +- Maple2.Model/Metadata/Constants.cs | 737 +-------------- .../Metadata/ServerTable/ConstantsTable.cs | 879 +++++++++++++++++- .../MovementState.CleanupTask.cs | 3 +- 4 files changed, 925 insertions(+), 715 deletions(-) diff --git a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs index e34ba9d51..d9af81fd0 100644 --- a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs +++ b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs @@ -1,11 +1,8 @@ -using System.Globalization; -using System.Xml; -using Maple2.Database.Extensions; +using Maple2.Database.Extensions; using Maple2.File.Ingest.Utils; using Maple2.File.IO; using Maple2.File.Parser; using Maple2.File.Parser.Enum; -using Maple2.File.Parser.Xml.Table; using Maple2.File.Parser.Xml.Table.Server; using Maple2.Model; using Maple2.Model.Common; @@ -14,6 +11,9 @@ using Maple2.Model.Game; using Maple2.Model.Game.Shop; using Maple2.Model.Metadata; +using System.Globalization; +using System.Reflection; +using System.Xml; using DayOfWeek = System.DayOfWeek; using ExpType = Maple2.Model.Enum.ExpType; using Fish = Maple2.File.Parser.Xml.Table.Server.Fish; @@ -2114,10 +2114,15 @@ void AddSpecial(Dictionary values, Dictionary(); - foreach ((string key, Parser.Xml.Table.Constants.Key constants) in parser.ParseConstants()) { - results.Add(key, new Model.Metadata.Constants(constants.key, constants.value)); + var constants = new Constants(); + PropertyInfo[] constantsProperties = constants.GetType().GetProperties(); + foreach (PropertyInfo constantsProperty in constantsProperties) { + foreach ((string key, Parser.Xml.Table.Constants.Key constant) in parser.ParseConstants()) { + if (!key.Normalize().Trim().Equals(constantsProperty.Name.Normalize().Trim())) continue; + constantsProperty.SetValue(constants, Convert.ChangeType(constant.value, constantsProperty.PropertyType)); + break; + } } - return new ConstantsTable(results); + return new ConstantsTable(constants); } } diff --git a/Maple2.Model/Metadata/Constants.cs b/Maple2.Model/Metadata/Constants.cs index 38f3b9574..13f94dac4 100644 --- a/Maple2.Model/Metadata/Constants.cs +++ b/Maple2.Model/Metadata/Constants.cs @@ -18,8 +18,6 @@ public static class Constant { public const long MesoTokenMax = 100000; public const int MaxSkillTabCount = 3; public const int BuddyMessageLengthMax = 25; - public const int MaxBuddyCount = 100; - public const int MaxBlockCount = 100; public const int GemstoneGrade = 4; public const int LapenshardGrade = 3; public const int InventoryExpandRowCount = 6; @@ -105,22 +103,52 @@ public static class Constant { public const int Grade3WeddingCouponItemId = 20303168; public const int MinStatIntervalTick = 100; public const int HomePollMaxCount = 5; - + public const int DummyNpcMale = 2040998; + public const int DummyNpcFemale = 2040999; + public const int NextStateTriggerDefaultTick = 100; public const int MaxMentees = 3; - public const long FurnishingBaseId = 2870000000000000000; public const bool AllowWaterOnGround = false; - public const int HomeDecorationMaxLevel = 10; - public const bool EnableRollEverywhere = false; public const bool HideHomeCommands = true; - public const int MaxAllowedLatency = 2000; - public const bool DebugTriggers = false; // Set to true to enable debug triggers. (It'll write triggers to files and load triggers from files instead of DB) - public const bool AllowUnicodeInNames = false; // Allow Unicode characters in character and guild names + public const bool MailQuestItems = false; // Mail quest item rewards if inventory is full + public const int MaxClosetMaxCount = 5; + public const int MaxClosetTabNameLength = 10; + public const int CharacterNameLengthMin = 2; + public const int BlockSize = 150; + public const float SouthEast = 0; + public const float NorthEast = 90; + public const float NorthWest = -180; + public const float SouthWest = -90; + public const short HairSlotCount = 30; + public const ShopCurrencyType InitialTierExcessRestockCurrency = ShopCurrencyType.Meso; + public const float UGCShopProfitFee = 0.25f; + public const int UGCShopProfitDelayDays = 10; + public const int PartyFinderListingsPageCount = 12; + public const int ProposalItemId = 11600482; + public const int bagSlotTabPetEquipCount = 48; + public const int BagSlotTabGameCountMax = 48; + public const int BagSlotTabSkinCountMax = 150; + public const int BagSlotTabSummonCountMax = 48; + public const int BagSlotTabMaterialCountMax = 48; + public const int BagSlotTabMasteryCountMax = 48; + public const int BagSlotTabLifeCountMax = 48; + public const int BagSlotTabQuestCountMax = 48; + public const int BagSlotTabGemCountMax = 48; + public const int BagSlotTabPetCountMax = 78; + public const int BagSlotTabPetEquipCountMax = 48; + public const int BagSlotTabActiveSkillCountMax = 48; + public const int BagSlotTabCoinCountMax = 48; + public const int BagSlotTabBadgeCountMax = 48; + public const int BagSlotTabMiscCountMax = 48; + public const int BagSlotTabLapenshardCountMax = 48; + public const int BagSlotTabPieceCountMax = 48; + public const int MeretAirTaxiPrice = 15; + public const int ClubMaxCount = 3; public static IReadOnlyDictionary ContentRewards { get; } = new Dictionary { {"miniGame", 1005}, @@ -148,7 +176,9 @@ public static class Constant { {"QueenBeanArenaRound10Reward", 10000018}, }; - public const bool MailQuestItems = false; // Mail quest item rewards if inventory is full + public static int DummyNpc(Gender gender) => gender is Gender.Female ? DummyNpcFemale : DummyNpcMale; + + #endregion #region Field public static readonly TimeSpan FieldUgcBannerRemoveAfter = TimeSpan.FromHours(4); @@ -188,65 +218,10 @@ public static class Constant { public static readonly int DefaultMaxCharacters = 4; #endregion - #endregion - - #region client constants - public const int MaxClosetMaxCount = 5; - public const int MaxClosetTabNameLength = 10; - public const int WeddingProposeItemID = 11600482; - public const int WeddingInvitationMaxCount = 70; - public const int WeddingProposeCooltime = 2; - public const int WeddingDivorceFieldID = 84000002; - public const int WeddingInvitationMeso = 1000; - public const int WeddingDivorceMeso = 1000000; - public const int WeddingCoolingOffDay = 7; - public const int WeddingPromiseLimitDay = 7; - public const int WeddingHallModifyLimitHour = 3; - public const int WeddingDivorceRequireMarriageDay = 30; - public const int CharacterNameLengthMin = 2; - public const int BlockSize = 150; - public const float SouthEast = 0; - public const float NorthEast = 90; - public const float NorthWest = -180; - public const float SouthWest = -90; - public const short HairSlotCount = 30; - public const ShopCurrencyType InitialTierExcessRestockCurrency = ShopCurrencyType.Meso; - public const float UGCShopProfitFee = 0.25f; - public const int UGCShopProfitDelayDays = 10; - public const int PartyFinderListingsPageCount = 12; - public const int ProposalItemId = 11600482; - #endregion - - #region table/constants.xml - - public const float NPCColorScale = 2.0f; - public const float NPCDuration = 0.2f; - public const float PCColorScale = 2.0f; - public const float PCDuration = 0.2f; - public const float GetEXPColorScale = 0.5f; - public const float GetEXPDuration = 0.2f; - public const float AccumulationRatio = 0.1f; + #region XML table/constants.xml public const float NPCCliffHeight = 50.0f; - public const float NPCRandomDeadPushRate = 0.2f; public const float CustomizingRotationSpeed = 75.0f; - public const float CustomizingWheelSpeed_Morph = 0.1f; - public const float CustomizingWheelSpeed_Item = 0.1f; - public const float CustomizingWheelSpeed_Makeup = 0.1f; - public const float CustomizingRotationSpeed_Makeup = 1.0f; - public const float CustomizingHairFirstPartHighlight = 0.1f; - public const float CustomizingHairSecondPartHighlight = 1.0f; - public const float LookAtInterval = 15.0f; - public const float LookAtDistanceNPC = 500.0f; - public const float LookAtDistanceCry = 500.0f; - public const bool EnableSkillJumpDown = true; - public const bool EscapeHitMethodSkill = false; - public const bool EscapeHitMethodJump = false; - public const bool EscapeHitMethodMove = false; - public const bool EscapeHitMoveKeyIsDown = false; public const bool AllowComboAtComboPoint = true; - public const bool CancelSwing_KeyIsDown = true; - public const bool SkillGlobalCooldown = false; - public const bool SkillGlobalCooldown_CheckSameSkill = true; public const int AttackRotationSpeed = 90; public const int ChaosModeTime = 20; public const int ChaosPointPerBlock = 20; @@ -261,79 +236,12 @@ public static class Constant { public const int OnEnterTriggerClientSideOnlyTick = 100; public const int OnEnterTriggerDefaultTick = 1000; public const int TalkTimeover = 60000; - public const int DamageDistance = 2500; - public const int TalkableDistance = 150; - public const bool TalkableFrontOnly = true; - public const int DropIconVisibleDistance = 400; - public const int ChatBalloonDistance = 2000; - public const int HpBarDistance = 9999999; - public const int EmoticonVisibleDistance = 2500; - public const int RegisterUgcDistance = 150; - public const int RegisterUgcDistanceClose = 300; - public const int ConstructUgcDistance = 150; - public const int FunctionCubeDistance = 125; - public const int InteractionDistance = 155; - public const int HouseMarkShowDistance = 2000; - public const int HouseMarkShowClippingUp = 1000; - public const int HouseMarkShowClippingDown = 500; - public const int HouseMarkPopupDistance = 160; - public const int UgcBoundaryStartDistance = 1; - public const int UgcBoundaryEndDistance = 7; - public const int DurationForBoundaryDisplay = 3000; - public static TimeSpan UgcHomeSaleWaitingTime = TimeSpan.FromSeconds(259200); - public const int UgcContainerExpireDurationNormal = 90; - public const int UgcContainerExpireDurationCash = 365; - public const int UgcContainerExpireDurationMeret = 365; - public const int UgcHomeExtensionNoticeDate = 30; - public const int UgcHomePasswordExpireDuration = 86400; - public const bool CubeLiftHeightLimitUp = true; - public const bool CubeLiftHeightLimitDown = true; - public const int CubeCraftSafetyCapID = 11300053; - public const int CubeCraftLightStickLeftID = 13100014; - public const int CubeCraftLightStickRightID = 13100046; - public const float DropIconDistance = 200.0f; - public const int DropIconHeadOffset = 40; - public const int DropItemMaxLength = 300; - public const int DropMoneyMaxLength = 300; - public const float DropItemTargetZPos = 200.0f; - public const float DropItemPickUpVel = 200.0f; - public const float DropItemPickUpGravity = -38.0f; - public const float DropItemPickUpCompleteRotateTime = 0.1f; - public const int DropItemPickUpCompleteRotateVel = 5; public const int DropMoneyActiveProbability = 0; public const int DropMoneyProbability = 0; - public const int ChatBalloonDuration = 5000; - public const int BoreWaitingTick = 50000; - public const int OffsetPcHpBar = 32; - public const int OffsetPcNameTag = 30; - public const int OffsetPcChatBalloon = -30; - public const int OffsetPcDamageNumber = 0; public const int OffsetPcMissionIndicator = 20; - public const int OffsetPcProfileTag = 0; - public const float fOffsetOnTombstoneNameTag = -5.0f; - public const int OffsetNpcHpBar = 5; - public const int OffsetNpcNameTag = 5; - public const int OffsetNpcEmoticon = -30; - public const int OffsetNpcChatBalloon = -30; - public const int OffsetNpcDamageNumber = 0; - public const int OffsetNpcMonologue = 40; - public const int OffsetActionTooltipX = 70; - public const int OffsetActionTooltipY = -40; - public const int OffsetPcPopupMenu = 60; - public const int DamageGap = 30; - public const int DamageRenderCount = 3; - public const int DamageRenderTotalCount = 25; - public const float DamageOtherScale = 0.5f; - public const float DamageOtherAlpha = 0.3f; - public const int DamageEffectMinHPPercent = 30; - public const int DamageEffectCriticalPercent = 10; public const int questHideTime = 30; public const int questIntervalTime = 60; public const int ShopResetChance = 10; - public const int ShopSeedResetTime = 60; - public const int ShopRepurchaseMax = 12; - public const int ShopSellConfirmPrice = 10000; - public const int ShopBuyConfirmPrice = 0; public const int DashKeyInputDelay = 500; public const int DashSwimConsumeSP = 20; public const int DashSwimMoveVel = 2; @@ -352,51 +260,14 @@ public static class Constant { public const string Glide_Ani_Left = "Gliding_Left_A"; public const string Glide_Ani_Right = "Gliding_Right_A"; public const string Glide_Ani_Run = "Fly_Run_A"; - public const float ClimbVelocityV = 3.0f; - public const float ClimbVelocityH = 1.5f; - public const int StoreExpandMaxSlotCount = 144; - public const int StoreExpandPrice1Row = 330; - public const int StoreDepositMax = 2000000000; - public const int StoreWithdrawMax = 2000000000; - public const int CameraExtraMoveScaleByMonster = 3; - public const int CameraExtraMoveScaleByMap = 2; - public const int CameraExtraDistance = 200; - public const float CameraFinalLoose = 0.08f; - public const float CameraCurrentLoose = 0.002f; - public const float CameraUpdateLoose = 0.03f; - public const int CameraVelocityInPortalMove = 6000; public const int ConsumeCritical = 5; - public const int MonologueInterval = 15; - public const int MonologueRandom = 10; - public const int MonologueShowTime = 5; - public const int ShowKillCountMin = 3; - public const int UserRevivalInvincibleTick = 5000; - public const int UserRevivalPenaltyPercent = 15; - public const string UserRevivalIconPath = "./data/resource/image/skill/icon/deathPenalty.png"; - public const string UserRevivalInvincibleIconPath = "./data/resource/image/skill/icon/deathInvincible.png"; - public const int GetExpMinVelocity = 250; - public const int GetExpVelocityPer1Length = 2; - public const string GetExpControlValue0 = "-0.5,0,0.25"; - public const string GetExpControlValue1 = "0.5,-0.25,0.5"; - public const string GetExpTargetPCDummyName = "Eff_Body"; - public const float GetExpTimeAcceleration = 1.02f; - public const float GetExpCollisionRadius = 15.0f; public const int DayToNightTime = 10000; - public const float MyPCDayTiming = 0.5f; - public const float MyPCNightTiming = 0.5f; + public const float myPCdayTiming = 0.5f; + public const float myPCNightTiming = 0.5f; public const float BGMTiming = 0.5f; public const int dayBaseMinute = 1; public const int dayMinute = 1439; public const int nightMinute = 1; - public const int SkipFrameGameObject = 5; - public const int SkipFrameDistanceGameObject = 2000; - public const float RegionSkillFadeOutDuration = 0.3f; - public const int PassengerProfileImageSize = 50; - public const int PassengerProfileImageLifeTime = 3; - public const int PassengerProfileImageShowNumber = 3; - public const int PassengerProfileImageShowCooldown = 57; - public const int PassengerProfileImageShowCooldownParty = 57; - public const int PassengerProfileImageShowRange = 400; public const int QuestRewardSkillSlotQuestID1 = 1010002; public const int QuestRewardSkillSlotQuestID2 = 1010003; public const int QuestRewardSkillSlotQuestID3 = 1010004; @@ -407,559 +278,37 @@ public static class Constant { public const int QuestRewardSkillSlotItemID3 = 20000001; public const int QuestRewardSkillSlotItemID4 = 40000055; public const int QuestRewardSkillSlotItemID5 = 40000056; - public const int UGCCameraDefaultSize = 320; - public const int UGCCameraMinSize = 160; - public const int UGCCameraMaxSize = 640; - public const int UGCCameraSnapshotPreviewTime = 3000; - public const int UGCImgUploadSizeLimit = 1024; - public const int UGCImgFileCountCheck = 200; - public const int WindAmp2Cloak = 1500; - public const float WindPeriod2Cloak = 0.7f; - public const float WindPeriodVar2Cloak = 0.4f; public const int autoTargetingMaxDegree = 210; - public const float VolumeMyPcToNpc = 1.0f; - public const float VolumeMyPcToObject = 0.5f; - public const float VolumeMyPcToBreakableObject = 0.8f; - public const float VolumeNpcToMyPc = 0.7f; - public const float VolumePcToNpc = 0.3f; - public const float VolumePcToBreakableObject = 0.3f; - public const float VolumeNpcToPc = 0.5f; - public const float VolumeOtherPc = 0.9f; - public const int ItemDropLevelMaxBoundary = 1; - public const float moneyTreeDropHeight = 300.0f; - public const float moneyTreeDropBase = 150.0f; - public const int moneyTreeDropRandom = 200; - public const int WhisperIgnoreTime = 1000; - public const int WhisperMaxCount = 3; - public const int WhisperDurationTime = 3000; public const float BossHitVibrateFreq = 10.0f; public const float BossHitVibrateAmp = 5.5f; public const float BossHitVibrateDamping = 0.7f; public const float BossHitVibrateDuration = 0.1f; - public const float BossHpBarAutoDetectRange = 1500.0f; - public const float BossHpBarDuration = 5.0f; - public const float FindHoldTargetRange = 230.0f; - public const int FindGrabNodeRange = 2000; - public const string UgcShopCharCameraLookat = "0,0,70"; - public const string UgcShopCharCameraPos = "220,0,0"; - public const int UgcShopCharCameraMinDistance = 150; - public const int UgcShopCharCameraZoomVelocity = 700; - public const string UgcShopCubeCameraLookat = "0,0,80"; - public const string UgcShopCubeCameraPos = "420,0,350"; - public const int UgcShopCubeCameraMinDistance = 450; - public const int UgcShopCubeCameraZoomVelocity = 700; - public const string UgcShopRideeCameraLookat = "10,-5,50"; - public const string UgcShopRideeCameraPos = "275,0,150"; - public const int UgcShopRideeCameraMinDistance = 250; - public const int UgcShopRideeCameraZoomVelocity = 700; - public const int FieldCachingCount = 2; - public const float FieldCachingTime = 300.0f; - public const int FieldCachingMaxCount = 4; - public const int FieldUnloadThreshold = 10; - public const float EffectLODOneStepDistance = 450.0f; - public const float EffectLODTwoStepDistance = 500.0f; - public const float EffectLODThreeStepDistance = 550.0f; - public const int TelescopeFindDistance = 200; - public const int BoatPrice = 500; - public const int QuestGuidePageCount = 3; - public const int QuestGuideMaxCount = 60; - public const float CameraInterpolationTime = 0.4f; public const int OneTimeWeaponItemID = 15000001; - public const int TransparencyCP = 11399999; - public const int TransparencyEY = 11199999; - public const int TransparencyCL = 11499999; - public const int TransparencyPA = 11599999; - public const int TransparencyMT = 11899999; - public const int TransparencyEA = 11299999; - public const int TransparencyFH = 11099999; - public const int TransparencyGL = 11699999; - public const int TransparencyRI = 12099999; - public const int TransparencySH = 11799999; - public const float DefaultDropItemAlpha = 0.3f; - public const float DropItemPickFailHeight = 50.0f; - public const float DropItemPickFailTime = 0.3f; - public const int TaxiStationFindDistance = 200; - public const int TaxiCallDuration = 3000; - public const int TaxiCallBestDriverDuration = 1000; - public const int TaxiCallBestDriverLevel = 25; - public const int AirTaxiCashCallDuration = 500; - public const int AirTaxiMesoCallDuration = 3000; - public const int TradeRequestDuration = 20; - public const int UserPortalInvincibleTick = 5000; - public const string UserPortalInvincibleIconPath = "./data/resource/image/skill/icon/deathInvincible.png"; - public const int SummonRideeDuration = 1000; - public const int WorldMapAdjustTileX = 0; - public const int WorldMapAdjustTileY = 0; - public const float TimeScalePCScale = 0.1f; - public const float TimeScalePCDuration = 1.0f; - public const int GoToHomeCastingTime = 0; - public const int returnHomeSkill = 100000000; - public const int returnHomeSkillMeret = 100000013; - public const int TutorialIntroSkipTime = 5; - public const string AvatarDefaultItemMale = "10200032,10300198"; - public const string AvatarDefaultItemFemale = "10200033,10300199"; public const int ModelHouse = 62000027; - public const int TalkCooldown = 1000; - public const int AddressPopupDuration = 3000; - public const int MaxFPS = 120; - public const int UGCShopSellMinPrice = 150; - public const int UGCShopSellMaxPrice = 3000; - public const int UGCShopSaleDay = 90; - public const int UGCShopAdFeeMeret = 30; - public const int UGCShopAdHour = 72; - public const int UGCShopSellingRestrictAmount = 200000; - public const int MeretMarketHomeBannerShowTick = 6000; - public const int BlackMarketSellMinPrice = 100; - public const int BlackMarketSellMaxPrice = 500000000; - public const int BlackMarketSellEndDay = 2; - public const int ItemTransferBlackMarketGrade = 4; - public const int UgcBannerCheckTime = 4; - public const int FastChat_CheckTime = 2000; - public const int FastChat_CheckCount = 5; - public const int SameChat_CheckTime = 3000; - public const int SameChat_CheckCount = 5; - public const int SameChat_RestrictTime = 10000; - public const int FastChat_RestrictTime = 30000; - public const int RestrictChat_AddRestrictTime = 10000; - public const int AccumWarning_AddRestrictTime = 60000; - public const int RestrictWarning_ReleaseTime = 10000; - public const int MaxChatLength = 100; public const int UsingNoPhysXModelUserCount = 10; public const int UsingNoPhysXModelActorCount = 10; public const int UsingNoPhysXModelJointCount = 10; - public const int EmotionBoreAnimProbability = 100; - public const float FallMoveSpeed = 1.0f; - public const int GuildCreatePrice = 2000; - public const int GuildCreateMinLevel = 0; - public const int GuildNameLengthMin = 2; - public const int GuildNameLengthMax = 25; - public const int guildFundMax = 20000; - public const float guildFundRate = 0.1f; - public const int guildExpMaxCountForPlayTime = 2; - public const int guildDonateMeso = 10000; - public const string mirrorGuideMoviePath = "Common/Customize_Hat.usm"; - public const string hairGuideMoviePath = "Common/Customize_Hair.usm"; - public const string makeUpGuideMoviePath = "Common/Customize_MakeUp.usm"; - public const int FastShimmerRadius = 600; - public const int FastShimmerHeight = 450; - public const int SmartRecommendNotify_DurationTick = 15000; - public const int BootyPopupDuration = 3000; public const bool EnableSoundMute = true; public const int BossKillSoundRange = 1500; - public const string charCreateGuideMoviePath = "Common/Customize_Intro.usm"; public const int monsterPeakTimeNotifyDuration = 300; - public const int KeyIsDownSkill_MaxDurationTick = 30000; - public const int shadowWorldBuffHpUp = 70000027; - public const int shadowWorldBuffMoveProtect = 70000032; public const int AirTaxiItemID = 20300003; - public const int PeriodOfMaidEmployment = 30; - public const int MaidReadyToPay = 7; - public const int MaidAffinityMax = 10; - public const int MeretRevivalDebuffCode = 100000001; - public const float MeretRevivalFeeReduceLimit = 0.5f; - public const int MeretConsumeWorldChat = 30; - public const int MeretConsumeChannelChat = 3; - public const int MeretConsumeSuperChat = 200; - public const int pvpBtiRewardItem = 90000006; - public const int pvpBtiRewardWinnerCount = 30; - public const int pvpBtiRewardLoserCount = 10; - public const int PvpFFAReward1Count = 30; - public const int PvpFFAReward2Count = 25; - public const int PvpFFAReward3Count = 20; - public const int PvpFFAReward4Count = 15; - public const int PvpFFAReward5Count = 15; - public const int PvpFFAReward6Count = 15; - public const int PvpFFAReward7Count = 15; - public const int PvpFFAReward8Count = 10; - public const int PvpFFAReward9Count = 10; - public const int PvpFFAReward10Count = 10; - public const int PvpFFARewardItem = 90000006; - public const int PvpFFAAdditionRewardRate = 0; - public const int MailExpiryDays = 30; - public const int WorldMapBossTooltipCount = 30; - public const int ShowNameTagEnchantItemGrade = 4; - public const int ShowNameTagEnchantLevel = 12; - public const int BossNotifyAbsLevel = 1; - public const int RoomExitWaitSecond = 10; - public const int AdditionalMesoMaxRate = 7; - public const int AdditionalExpMaxRate = 9; - public const int HonorTokenMax = 30000; - public const int KarmaTokenMax = 75000; - public const int LuTokenMax = 2000; - public const int HaviTokenMax = 35000; - public const int ReverseCoinMax = 2000; - public const int MentorTokenMax = 10000; // From KMS - public const int MenteeTokenMax = 35000; // From KMS - public const int CharacterDestroyDivisionLevel = 20; - public const int CharacterDestroyWaitSecond = 86400; - public const int BossShimmerScaleUpActiveDistance = 5000; - public const float BossShimmerScaleUpSize = 3.0f; public const int ShowNameTagSellerTitle = 10000153; public const int ShowNameTagChampionTitle = 10000152; public const int ShowNameTagTrophy1000Title = 10000170; public const int ShowNameTagTrophy2000Title = 10000171; public const int ShowNameTagTrophy3000Title = 10000172; public const int ShowNameTagArchitectTitle = 10000158; - public const float SwimDashSpeed = 5.4f; - public const int UserTriggerStateMax = 10; - public const int UserTriggerEnterActionMax = 3; - public const int UserTriggerConditionMax = 3; - public const int UserTriggerConditionActionMax = 3; - public const int PCBangAdditionalEffectID = 100000006; - public const int PCBangAdditionalEffectExp = 1; - public const int PCBangAdditionalEffectMeso = 2; - public const int PCBangItemDefaultPeriod = 1440; - public const int ShadowWorldAutoReviveDeadAction = 1; - public const int GoodInteriorRecommendUICloseTime = 15; - public const string UGCInfoDetailViewPage = "http://www.nexon.net/en/legal/user-generated-content-policy"; - public const int UGCInfoStoryBookID = 39000038; - public const int HomePasswordUsersKickDelay = 10; - public const string TriggerEditorHelpURL = "http://maplestory2.nexon.net/en/news/article/32326"; - public const int QuestRewardSAIgnoreLevel = 10; - public const int RecallCastingTime = 3000; - public const int PartyRecallMeret = 30; - public const float CashCallMedicLeaveDelay = 0.5f; public const int characterMaxLevel = 99; // Updated - public const int DropSPEPBallMaxLength = 300; - public const int DropSPEPBallTargetZPos = 100; - public const int DropSPEPBallPickUpVel = 250; - public const int DropSPEPBallPickUpGravity = -120; - public const float DropSPEPBallPickUpCompleteRotateTime = 0.05f; - public const int DropSPEPBallPickUpCompleteRotateVel = 5; - public const int EnchantItemBindingRequireLevel = 1; - public const int enchantSuccessBroadcastingLevel = 12; - public const int EnchantEquipIngredientMaxCount = 1000; - public const int EnchantFailStackUsingMaxCount = 100; - public const int EnchantFailStackTakeMaxCount = 1000; - public const int EnchantEquipIngredientOpenLevel = 11; - public const int EnchantEquipIngredientOpenRank = 4; - public const int EnchantEquipIngredientMaxSuccessProb = 3000; - public const int EnchantFailStackOpenLevel = 1; - public const int EnchantFailStackTakeMaxSuccessProb = 10000; - public const int BankCallDuration = 500; - public const string NoticeDialogUrl = "http://nxcache.nexon.net/maplestory2/ingame-banners/index.html"; - public const string NoticeDialogUrlPubTest = "maview:/Game/BannerTest"; - public const int NoticeDialogOpenSeconds = 5000; - public const int RemakeOptionMaxCount = 10; - public const int FisherBoreDuration = 10000; - public const string fishingStartCastingBarText0 = "s_fishing_start_castingbar_text0"; - public const string fishingStartCastingBarText1 = "s_fishing_start_castingbar_text1"; - public const string fishingStartCastingBarText2 = "s_fishing_start_castingbar_text2"; - public const string fishingStartCastingBarText3 = "s_fishing_start_castingbar_text3"; - public const string fishingStartCastingBarText4 = "s_fishing_start_castingbar_text4"; - public const string fishingStartBalloonText0 = "s_fishing_start_balloon_text0"; - public const string fishingStartBalloonText1 = "s_fishing_start_balloon_text1"; - public const string fishingStartBalloonText2 = "s_fishing_start_balloon_text2"; - public const string fishingStartBalloonText3 = "s_fishing_start_balloon_text3"; - public const string fishingStartBalloonText4 = "s_fishing_start_balloon_text4"; - public const string fishingStartBalloonText5 = "s_fishing_start_balloon_text5"; - public const string fishingStartBalloonText6 = "s_fishing_start_balloon_text6"; - public const string fishingStartBalloonText7 = "s_fishing_start_balloon_text7"; - public const string fishingStartBalloonText8 = "s_fishing_start_balloon_text8"; - public const string fishingStartBalloonText9 = "s_fishing_start_balloon_text9"; - public const string fishFightingCastingBarText0 = "s_fishing_fishfighting_castingbar_text0"; - public const string fishFightingBalloonText0 = "s_fishing_fishfighting_balloon_text0"; - public const string fishFightingBalloonText1 = "s_fishing_fishfighting_balloon_text1"; - public const string fishFightingBalloonText2 = "s_fishing_fishfighting_balloon_text2"; - public const string fishFightingBalloonText3 = "s_fishing_fishfighting_balloon_text3"; - public const string fishFightingBalloonText4 = "s_fishing_fishfighting_balloon_text4"; - public const string fishFightingBalloonText5 = "s_fishing_fishfighting_balloon_text5"; - public const int WorldMapSpecialFunctionNpcID0 = 11001276; - public const string WorldMapSpecialFunctionNpcFrame0 = "airship_enabled"; - public const string WorldMapSpecialFunctionNpcTooltip0 = "s_worldmap_special_function_npc0"; - public const int WorldMapSpecialFunctionNpcID1 = 11001403; - public const string WorldMapSpecialFunctionNpcFrame1 = "airship_enabled"; - public const string WorldMapSpecialFunctionNpcTooltip1 = "s_worldmap_special_function_npc0"; - public const int WarpOpenContinent0 = 102; - public const int WarpOpenContinent1 = 103; - public const int WarpOpenContinent2 = 202; - public const int WarpOpenContinent3 = 105; - public const string WriteMusicDetailWebPage = "http://maplestory2.nexon.net/en/news/article/32329"; - public const int WriteMusicStoryBookID = 39000047; - public const int MusicListenInRadius = 900; - public const int MusicListenOutRadius = 2200; - public const int DungeonRoomMaxRewardCount = 99; - public const int DungeonMatchRecommendPickCount = 6; - public const int DungeonSeasonRankMinLevel = 99; - public const int LimitMeretRevival = 1; - public const int MinimapScaleSkipDuration = 5000; - public const int MinimapScaleSkipSplitPixel = 20; - public const int TradeMinMeso = 100; - public const int TradeMaxMeso = 500000000; - public const int TradeFeePercent = 20; - public const int DailyMissionRequireLevel = 50; - public const int MesoMarketBasePrice = 5000000; - public const int MesoMarketProductUnit0 = 5000000; - public const int MesoMarketBuyPayType = 16; - public const int MesoMarketIconType = 0; - public const string MesoMarketTokenDetailUrl = "http://maplestory2.nexon.net/en/news/article/45213"; - public const int BeautyHairShopGotoFieldID = 52000008; - public const int BeautyHairShopGotoPortalID = 1; - public const int BeautyColorShopGotoFieldID = 52000009; - public const int BeautyColorShopGotoPortalID = 1; - public const int BeautyFaceShopGotoFieldID = 52000010; - public const int BeautyFaceShopGotoPortalID = 1; - public const int BeautyStyleExpandSlotPrice = 980; - public const int BeautyStyleMaxSlotCount = 0; - public const int BeautyStyleDefaultSlotCount = 30; - public const int BeautyStyleExpandSlotCount1time = 3; - public const string CashShopFigureAddressPage = "http://maplestory2.nexon.com/cashshop/address"; - public const int NxaCashChargeWebPageWidth = 650; - public const int NxaCashChargeWebPageHeight = 650; - public const int ItemUnLockTime = 259200; - public const int PropertyProtectionTime = 60; - public const string TencentSecurityWebPage = "http://mxd2.qq.com/safe/index.shtml"; - public const int HomeBankCallDuration = 1000; - public const int HomeBankCallCooldown = 30000; - public const string HomeBankCallSequence = "Object_React_A"; - public const int HomeDoctorCallDuration = 1000; - public const int HomeDoctorCallCooldown = 30000; - public const string HomeDoctorCallSequence = "EmergencyHelicopter_A"; - public const int HomeDoctorNpcID = 11001668; - public const int HomeDoctorScriptID0 = 1; - public const int HomeDoctorScriptID1 = 10; - public const int EnchantMasterScriptID = 31; - public const int RestExpAcquireRate = 10000; - public const int RestExpMaxAcquireRate = 100000; - public const int ApartmentPreviewRequireLevel = 50; - public const int ApartmentPreviewRequireQuestID = 90000060; - public const int KeyboardGuideShowLevel = 13; - public const int extendAutoFishMaxCount = 8; - public const int extendAutoPlayInstrumentMaxCount = 8; - public const int ResetShadowBuffMeret = 100; - public const int InventoryExpandPrice1Row = 390; - public const int VIPServicePeriodLimitDay = 100000000; - public const int VIPMarketCommissionSale = 20; - public const int BreedDuration = 767; - public const int HarvestDuration = 767; - public const int RestartQuestStartField = 52000056; - public const int RestartQuestStartFieldRuneblader = 63000006; - public const int RestartQuestStartFieldStriker = 63000015; - public const int RestartQuestStartFieldSoulBinder = 63000035; - public const int QuestPortalKeepTime = 300; - public const string QuestPortalKeepNif = "Eff_Com_Portal_E_Quest"; - public const int QuestPortalDimensionY = 50; - public const int QuestPortalDimensionZ = 350; - public const int QuestPortalSummonTime = 600; - public const int QuestPortalDistanceFromNpc = 200; - public const int PetChangeNameMeret = 100; - public const int PetRunSpeed = 350; - public const int PetPickDistance = 1050; - public const int PetSummonCastTime = 800; - public const int PetBoreTime = 60000; - public const int PetIdleTime = 70000; - public const int PetTiredTime = 10000; - public const int PetSkillTime = 13000; - public const string PetEffectUse = "Pet/Eff_Pet_Use.xml"; - public const string PetEffectSkill = "Pet/Eff_Pet_Skill.xml"; - public const string PetEffectHappy = "Pet/Eff_Pet_Happy.xml"; - public const string PetGemChatBalloon = "pet"; - public const int PetTrapAreaDistanceEasy = 150; - public const int PetTrapAreaDistanceNormal = 150; - public const int PetTrapAreaDistanceHard = 150; - public const string PetTrapAreaEffectEasy = "Pet/Eff_Pet_TrapInstallArea_easy.xml"; - public const string PetTrapAreaEffectNormal = "Pet/Eff_Pet_TrapInstallArea_normal.xml"; - public const string PetTrapAreaEffectHard = "Pet/Eff_Pet_TrapInstallArea_hard.xml"; - public const string PetTrapAreaEffectOtherUser = "Pet/Eff_Pet_TrapArea_OtherUser.xml"; - public const string PetTamingMaxPointEffect = "Pet/Eff_PetTaming_MaxPoint.xml"; - public const string PetTamingAttackMissEffect = "Pet/Eff_PetTaming_Attack_Miss.xml"; - public const string PetTrapDropItemEffect = "Pet/Eff_PetTrap_DropItem.xml"; - public const int TamingPetEscapeTime = 300; - public const int TamingPetMaxPoint = 10000; - public const int PetNameLengthMin = 2; - public const int PetNameLengthMax = 25; - public const int PetTrapDropVisibleDelay = 2000; - public const int PetMaxLevel = 50; - public const string VisitorBookURL = ""; public const int OneShotSkillID = 19900061; - public const int BagSlotTabGameCount = 48; - public const int BagSlotTabSkinCount = 150; - public const int BagSlotTabSummonCount = 48; - public const int BagSlotTabMaterialCount = 48; - public const int BagSlotTabMasteryCount = 126; - public const int BagSlotTabLifeCount = 48; - public const int BagSlotTabQuestCount = 48; - public const int BagSlotTabGemCount = 48; - public const int BagSlotTabPetCount = 60; - public const int BagSlotTabPetEquipCount = 48; - public const int BagSlotTabActiveSkillCount = 84; - public const int BagSlotTabCoinCount = 48; - public const int BagSlotTabBadgeCount = 60; - public const int BagSlotTabMiscCount = 84; - public const int BagSlotTabLapenshardCount = 48; - public const int BagSlotTabPieceCount = 48; - public const int BagSlotTabGameCountMax = 48; - public const int BagSlotTabSkinCountMax = 150; - public const int BagSlotTabSummonCountMax = 48; - public const int BagSlotTabMaterialCountMax = 48; - public const int BagSlotTabMasteryCountMax = 48; - public const int BagSlotTabLifeCountMax = 48; - public const int BagSlotTabQuestCountMax = 48; - public const int BagSlotTabGemCountMax = 48; - public const int BagSlotTabPetCountMax = 78; - public const int BagSlotTabPetEquipCountMax = 48; - public const int BagSlotTabActiveSkillCountMax = 48; - public const int BagSlotTabCoinCountMax = 48; - public const int BagSlotTabBadgeCountMax = 48; - public const int BagSlotTabMiscCountMax = 48; - public const int BagSlotTabLapenshardCountMax = 48; - public const int BagSlotTabPieceCountMax = 48; - public const int MasteryObjectInteractionDistance = 150; - public const float GatheringObjectMarkOffsetX = 0.0f; - public const float GatheringObjectMarkOffsetY = 0.0f; - public const float BreedingObjectMarkOffsetX = 0.0f; - public const float BreedingObjectMarkOffsetY = 0.0f; - public const int UGCAttention = 0; - public const int UGCInfringementCenter = 1; - public const string CharacterSelectBoreIdleEffect_Ranger = ""; - public const string CharacterSelectBoreIdleEffect_SoulBinder = ""; - public const int DisableSoloPlayHighLevelDungeon = 0; - public const int MergeSmithScriptID = 10; - public const int AutoPressActionKeyDuration = 500; - public const int WebBrowserSizeWidthMin = 438; - public const int WebBrowserSizeWidthMax = 1700; - public const int WebBrowserSizeHeightMin = 708; - public const int WebBrowserSizeHeightMax = 1003; - public const bool WebBrowserEnableSizingButton = true; - public const int MeretAirTaxiPrice = 15; - public const int GlobalPortalMinLevel = 10; - public const int userMassiveExtraRewardMax = 5; - public const int SkillBookTreeAddTabFeeMeret = 990; - public const int MentorRequireLevel = 50; - public const int MenteeRequireLevel = 30; - public const int MentorMaxWaitingCount = 100; - public const int MenteeMaxReceivedCount = 20; public const int FindDungeonHelpEasyDungeonLevel = 50; - public const int CoupleEffectCheckTick = 5000; - public const int CoupleEffectCheckRadius = 150; - public const int FameContentsSkyFortressMapID0 = 02000421; - public const int FameContentsSkyFortressMapID1 = 02000422; - public const int FameContentsSkyFortressMapID2 = 52010039; - public const int FameContentsSkyFortressMapID3 = 52010040; - public const int AllianceQuestPickCount = 2; - public const int FieldQuestPickCount = 1; - public const int FameContentsSkyFortressGotoMapID = 02000422; - public const int FameContentsSkyFortressGotoPortalID = 3; public const int FameContentsRequireQuestID = 91000013; public const int FameExpedContentsRequireQuestID = 50101050; - public const int DailyPetEnchantMaxCount = 24; - public const int MouseCursorHideTime = 30; - public const int EnchantTransformScriptID = 10; - public const float AutoHideGroupAlpha = 0.6f; - public const int AutoHideGroupHitVisibleTick = 3000; - public const int UgcShopCharRotateStartDegreeY = 178; - public const int UgcShopCharRotateEndDegreeY = 8; public const int SurvivalScanAdditionalID = 71000052; public const int MapleSurvivalTopNRanking = 5; public const string MapleSurvivalSeasonRewardUrl = "http://maplestory2.nexon.net/en/news/article/32249/mushking-royale-championship-rewards"; - public const int TreeWateringEmotion = 10000; - public const int AdventureLevelLimit = 10000; - public const int AdventureLevelLvUpExp = 1000000; - public const int AdventureLevelMaxExp = 1500000; - public const float AdventureLevelFactor = 0.02f; - public const int AdventureExpFactorElite = 10; - public const int AdventureExpFactorBoss = 100; - public const int AdventureLevelStartLevel = 50; - public const int AdventureLevelLvUpRewardItem = 30001133; - public const int NameColorDeadDuration = 2000; - public const float MesoRevivalFeeReduceLimit = 0.5f; - public const float IngredientFeeReduceLimit = 0.5f; - public const int StatPointLimit_str = 100; - public const int StatPointLimit_dex = 100; - public const int StatPointLimit_int = 100; - public const int StatPointLimit_luk = 100; - public const int StatPointLimit_hp = 100; - public const int StatPointLimit_cap = 60; - public const float GamePadRumbleMultiple = 3.0f; - public const int NurturingEatMaxCount = 0; - public const int NurturingPlayMaxCount = 3; - public const string NurturingQuestTag = "NurturingGhostCats"; - public const int NurturingDuration = 3000; - public const int NurturingInteractionDistance = 150; - public const int NurturingEatGrowth = 10; - public const int NurturingPlayGrowth = 10; - public const int NurturingPlayMailId = 19101804; - public const int NurturingPlayMaxGrowth = 3; - public const int NurturingHungryTime = 1000; - public const int SkillPointLimitLevel1 = 80; - public const int SkillPointLimitLevel2 = 70; - public const int SellPriceNormalMax = 4628; - public const int SellPriceRareMax = 5785; - public const int SellPriceEliteMax = 7405; - public const int SellPriceExcellentMax = 9256; - public const int SellPriceLegendaryMax = 11339; - public const int SellPriceArtifactMax = 13653; - public const string RegionServerUrl_de = "http://ugc.maplestory2.nexon.net/region/region_DE.xml"; - public const string RegionServerUrl_en = "http://ugc.maplestory2.nexon.net/region/region_EN.xml"; - public const string RegionServerUrl_bpo = "http://ugc.maplestory2.nexon.net/region/region_BPO.xml"; public const int HoldAttackSkillID = 10700252; - public const int TooltipLabelMaxWidth = 408; - public const int ClubNameLengthMin = 2; - public const int ClubNameLengthMax = 25; - public const int ClubMaxCount = 3; - public const int UgcNameLengthMin = 3; - public const int UgcNameLengthMax = 25; - public const int UgcTagLengthMax = 12; - public const int ChangeJobLevel = 60; - public const int LapenshardOpenQuestID = 20002391; - public const int MaidNameLengthMin = 1; - public const int MaidNameLengthMax = 35; - public const int MaidDescLengthMin = 1; - public const int MaidDescLengthMax = 35; - public const int GamePadStickMoveValue = 50; - public const int HighlightMenuUsingLevel = 5; - public const int PartyVoteReadyDurationSeconds = 20; - public const int PartyVoteReadyTagExpireSeconds = 10; - public const int ShieldBarOffsetY = -10; - public const int MouseInteractLimitDistance = 2000; - public const int AutoInstallEquipmentMinLevel = 5; - public const int AutoInstallEquipmentMaxLevel = 49; - public const string PartySearchRegisterComboValues = "4,6,10"; - public const int StatScaleMarkingAdditionalEffect = 70000174; - public const string DungeonRewardFailEmotions = "90200001,90200009,90200005,90200018"; - public const int SummonPetSkillID = 82100001; - public const int UGCMapSetItemEffectCountLimit = 10; public const string DiscordAppID = "555204064091045904"; - public const int ItemBoxMultiOpenMaxCount = 10; - public const int ItemBoxMultiOpenLimitCount = 500; - public const int BuffBalloonDistance = 3800; - public const int PaybackStartDate = 20191024; - public const int PaybackMailId = 50000020; - public const int PaybackMailPeriodDay = 90; - public const int PaybackMaxRewardMeret = 10000; - public const string PaybackGuideUrl = "http://maplestory2.nexon.com/News/Events"; - public const int DummyNpcMale = 2040998; - public const int DummyNpcFemale = 2040999; - public static int DummyNpc(Gender gender) => gender is Gender.Female ? DummyNpcFemale : DummyNpcMale; - - #endregion - - #region server table/constants.xml - public const int NextStateTriggerDefaultTick = 100; - public const int UserRevivalPaneltyTick = 3600000; - public const int UserRevivalPaneltyMinLevel = 10; - public const int maxDeadCount = 3; - public const byte hitPerDeadCount = 5; - public const int FishFightingProp = 3000; - - public const float NpcLastSightRadius = 1800; - public const float NpcLastSightHeightUp = 525; - public const float NpcLastSightHeightDown = 225; - - public const int RecoveryHPWaitTick = 1000; - public const int RecoverySPWaitTick = 1000; - public const int RecoveryEPWaitTick = 1000; - public const float FallBoundingAddedDistance = 750f; - - public const int UserBattleDurationTick = 5000; - - public const int SystemShopNPCIDConstruct = 11000486; - public const int SystemShopNpcIDUGCDesign = 11000166; - public const int SystemShopNPCIDHonorToken = 11001562; - public const int SystemShopNPCIDFishing = 11001609; - public const int SystemShopNPCIDMentor = 11003561; - public const int SystemShopNPCIDMentee = 11003562; #endregion } diff --git a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs index ae2b913b7..1f056e34c 100644 --- a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs +++ b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs @@ -1,14 +1,869 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Maple2.Model.Metadata; -namespace Maple2.Model.Metadata; +public record ConstantsTable(Constants Constants) : ServerTable; -public record ConstantsTable(IReadOnlyDictionary Constants) : ServerTable; - -public record Constants ( - string Key, - string Value - ); +public record Constants( + float NPCColorScale = 0f, + float NPCDuration = 0f, + float PCColorScale = 0f, + float PCDuration = 0f, + float GetEXPColorScale = 0f, + float GetEXPDuration = 0f, + float AccumulationRatio = 0f, + float NPCRandomDeadPushRate = 0f, + float CustomizingWheelSpeed_Morph = 0f, + float CustomizingWheelSpeed_Item = 0f, + float CustomizingWheelSpeed_Makeup = 0f, + float CustomizingRotationSpeed_Makeup = 0f, + float CustomizingHairFirstPartHighlight = 0f, + float CustomizingHairSecondPartHighlight = 0f, + float LookAtInterval = 0f, + float LookAtDistanceNPC = 0f, + float LookAtDistanceCry = 0f, + bool EnableSkillJumpDown = false, + bool EscapeHitMethodSkill = false, + bool EscapeHitMethodJump = false, + bool EscapeHitMethodMove = false, + bool EscapeHitMoveKeyIsDown = false, + bool CancelSwing_KeyIsDown = false, + bool SkillGlobalCooldown = false, + bool SkillGlobalCooldown_CheckSameSkill = false, + int DamageDistance = 0, + int TalkableDistance = 0, + bool TalkableFrontOnly = false, + int DropIconVisibleDistance = 0, + int ChatBalloonDistance = 0, + int HpBarDistance = 0, + int EmoticonVisibleDistance = 0, + int RegistUgcDistance = 0, + int RegistUgcDistanceClose = 0, + int ConstructUgcDistance = 0, + int FunctionCubeDistance = 0, + int InteractionDistance = 0, + int HouseMarkShowDistance = 0, + int HouseMarkShowClippingUp = 0, + int HouseMarkShowClippingDown = 0, + int HouseMarkPopupDistance = 0, + int UgcBoundaryStartDistance = 0, + int UgcBoundaryEndDistance = 0, + int DurationForBoundaryDisplay = 0, + TimeSpan UgcHomeSaleWaitingTime = new(), + int UgcContainerExpireDurationNormal = 0, + int UgcContainerExpireDurationCash = 0, + int UgcContainerExpireDurationMeret = 0, + int UgcHomeExtensionNoticeDate = 0, + int UgcHomePasswordExpireDuration = 0, + bool CubeLiftHeightLimitUp = false, + bool CubeLiftHeightLimitDown = false, + int CubeCraftSafetyCapID = 0, + int CubeCraftLightStickLeftID = 0, + int CubeCraftLightStickRightID = 0, + float DropIconDistance = 0f, + int DropIconHeadOffset = 0, + int DropItemMaxLength = 0, + int DropMoneyMaxLength = 0, + float DropItemTargetZPos = 0f, + float DropItemPickUpVel = 0f, + float DropItemPickUpGravity = 0f, + float DropItemPickUpCompleteRotateTime = 0f, + int DropItemPickUpCompleteRotateVel = 0, + int ChatBalloonDuration = 0, + int BoreWaitingTick = 0, + int OffsetPcHpBar = 0, + int OffsetPcNameTag = 0, + int OffsetPcChatBalloon = 0, + int OffsetPcDamageNumber = 0, + int OffsetPcProfileTag = 0, + float fOffsetOnTombstoneNameTag = 0f, + int OffsetNpcHpBar = 0, + int OffsetNpcNameTag = 0, + int OffsetNpcEmoticon = 0, + int OffsetNpcChatBalloon = 0, + int OffsetNpcDamageNumber = 0, + int OffsetNpcMonologue = 0, + int OffsetActionTooltipX = 0, + int OffsetActionTooltipY = 0, + int OffsetPcPopupMenu = 0, + int DamageGap = 0, + int DamageRenderCount = 0, + int DamageRenderTotalCount = 0, + float DamageOtherScale = 0f, + float DamageOtherAlpha = 0f, + int DamageEffectMinHPPercent = 0, + int DamageEffectCriticalPercent = 0, + int ShopSeedResetTime = 0, + int ShopRepurchaseMax = 0, + int ShopSellConfirmPrice = 0, + int ShopBuyConfirmPrice = 0, + float ClimbVelocityV = 0f, + float ClimbVelocityH = 0f, + int StoreExpandMaxSlotCount = 0, + int StoreExpandPrice1Row = 0, + int StoreDepositMax = 0, + int StoreWithdrawMax = 0, + int CameraExtraMoveScaleByMonster = 0, + int CameraExtraMoveScaleByMap = 0, + int CameraExtraDistance = 0, + float CameraFinalLoose = 0f, + float CameraCurrentLoose = 0f, + float CameraUpdateLoose = 0f, + int CameraVelocityInPortalMove = 0, + int MonologueInterval = 0, + int MonologueRandom = 0, + int MonologueShowTime = 0, + int ShowKillCountMin = 0, + int UserRevivalInvincibleTick = 0, + int UserRevivalPenaltyPercent = 0, + string UserRevivalIconPath = "", + string UserRevivalInvincibleIconPath = "", + int GetExpMinVelocity = 0, + int GetExpVelocityPer1Length = 0, + string GetExpControlValue0 = "", + string GetExpControlValue1 = "", + string GetExpTargetPCDummyName = "", + float GetExpTimeAcceleration = 0f, + float GetExpCollisionRadius = 0f, + int SkipFrameGameObject = 0, + int SkipFrameDistanceGameObject = 0, + float RegionSkillFadeOutDuration = 0f, + int PassengerProfileImageSize = 0, + int PassengerProfileImageLifeTime = 0, + int PassengerProfileImageShowNumber = 0, + int PassengerProfileImageShowCooldown = 0, + int PassengerProfileImageShowCooldownParty = 0, + int PassengerProfileImageShowRange = 0, + int UGCCameraDefaultSize = 0, + int UGCCameraMinSize = 0, + int UGCCameraMaxSize = 0, + int UGCCameraSnapshotPreviewTime = 0, + int UGCImgUploadSizeLimit = 0, + int UGCImgFileCountCheck = 0, + int WindAmp2Cloak = 0, + float WindPeriod2Cloak = 0f, + float WindPeriodVar2Cloak = 0f, + float VolumeMyPcToNpc = 0f, + float VolumeMyPcToObject = 0f, + float VolumeMyPcToBreakableObject = 0f, + float VolumeNpcToMyPc = 0f, + float VolumePcToNpc = 0f, + float VolumePcToBreakableObject = 0f, + float VolumeNpcToPc = 0f, + float VolumeOtherPc = 0f, + int ItemDropLevelMaxBoundary = 0, + float moneyTreeDropHeight = 0f, + float moneyTreeDropBase = 0f, + int moneyTreeDropRandom = 0, + int WhisperIgnoreTime = 0, + int WhisperMaxCount = 0, + int WhisperDurationTime = 0, + float BossHpBarAutoDetectRange = 0f, + float BossHpBarDuration = 0f, + float FindHoldTargetRange = 0f, + int FindGrabNodeRange = 0, + string UgcShopCharCameraLookat = "", + string UgcShopCharCameraPos = "", + int UgcShopCharCameraMinDistance = 0, + int UgcShopCharCameraZoomVelocity = 0, + string UgcShopCubeCameraLookat = "", + string UgcShopCubeCameraPos = "", + int UgcShopCubeCameraMinDistance = 0, + int UgcShopCubeCameraZoomVelocity = 0, + string UgcShopRideeCameraLookat = "", + string UgcShopRideeCameraPos = "", + int UgcShopRideeCameraMinDistance = 0, + int UgcShopRideeCameraZoomVelocity = 0, + int FieldCachingCount = 0, + float FieldCachingTime = 0f, + int FieldCachingMaxCount = 0, + int FieldUnloadThreshold = 0, + float EffectLODOneStepDistance = 0f, + float EffectLODTwoStepDistance = 0f, + float EffectLODThreeStepDistance = 0f, + int TelescopeFindDistance = 0, + int BoatPrice = 0, + int QuestGuidePageCount = 0, + int QuestGuideMaxCount = 0, + float CameraInterpolationTime = 0f, + int TransparencyCP = 0, + int TransparencyEY = 0, + int TransparencyCL = 0, + int TransparencyPA = 0, + int TransparencyMT = 0, + int TransparencyEA = 0, + int TransparencyFH = 0, + int TransparencyGL = 0, + int TransparencyRI = 0, + int TransparencySH = 0, + float DefaultDropItemAlpha = 0f, + float DropItemPickFailHeight = 0f, + float DropItemPickFailTime = 0f, + int TaxiStationFindDistance = 0, + int TaxiCallDuration = 0, + int TaxiCallBestDriverDuration = 0, + int TaxiCallBestDriverLevel = 0, + int AirTaxiCashCallDuration = 0, + int AirTaxiMesoCallDuration = 0, + int TradeRequestDuration = 0, + int UserPortalInvincibleTick = 0, + string UserPortalInvincibleIconPath = "", + int SummonRideeDuration = 0, + int WorldMapAdjustTileX = 0, + int WorldMapAdjustTileY = 0, + float TimeScalePCScale = 0f, + float TimeScalePCDuration = 0f, + int GoToHomeCastingTime = 0, + int returnHomeSkill = 0, + int returnHomeSkillMeret = 0, + int TutorialIntroSkipTime = 0, + string AvatarDefaultItemMale = "", + string AvatarDefaultItemFemale = "", + int TalkCooldown = 0, + int AddressPopupDuration = 0, + int MaxFPS = 0, + int UGCShopSellMinPrice = 0, + int UGCShopSellMaxPrice = 0, + int UGCShopSaleDay = 0, + int UGCShopAdFeeMeret = 0, + int UGCShopAdHour = 0, + int UGCShopSellingRestrictAmount = 0, + int MeretMarketHomeBannerShowTick = 0, + int BlackMarketSellMinPrice = 0, + int BlackMarketSellMaxPrice = 0, + int BlackMarketSellEndDay = 0, + int ItemTransferBlackMarketGrade = 0, + int UgcBannerCheckTime = 0, + int FastChat_CheckTime = 0, + int FastChat_CheckCount = 0, + int SameChat_CheckTime = 0, + int SameChat_CheckCount = 0, + int SameChat_RestrictTime = 0, + int FastChat_RestrictTime = 0, + int RestrictChat_AddRestrictTime = 0, + int AccumWarning_AddRestrictTime = 0, + int RestrictWarning_ReleaseTime = 0, + int MaxChatLength = 0, + int EmotionBoreAnimProbability = 0, + float FallMoveSpeed = 0f, + int GuildCreatePrice = 0, + int GuildCreateMinLevel = 0, + int GuildNameLengthMin = 0, + int GuildNameLengthMax = 0, + int guildFundMax = 0, + float guildFundRate = 0f, + int guildExpMaxCountForPlayTime = 0, + int guildDonateMeso = 0, + int guildStorageGiftNeedPeriod = 0, + int guildStorageItemMail = 0, + string mirrorGuideMoviePath = "", + string hairGuideMoviePath = "", + string makeUpGuideMoviePath = "", + int FastShimmerRadius = 0, + int FastShimmerHeight = 0, + int SmartRecommendNotify_DurationTick = 0, + int BootyPopupDuration = 0, + string charCreateGuideMoviePath = "", + int KeyIsDownSkill_MaxDurationTick = 0, + int MaxBuddyCount = 0, + int MaxBlockCount = 0, + int UserPendingRemoveTime = 0, + int HideCubeDuration = 0, + int DailyTrophyPickDiffLevel = 0, + int dailyAchievePickCount = 0, + int MovementEventDistance = 0, + int HomeReturnPortalKeepTime = 0, + string HomeReturnPortalKeepNif = "", + int HomeReturnPortalDimensionY = 0, + float GlobalCubeSkillIntervalTime = 0f, + int RoomEnterPortalDurationTick = 0, + int NpcBossCubeSkillCreateHeight = 0, + int NPCUpdateTickNoUser = 0, + int NPCUpdateTickWanderIdle = 0, + int NpcSmallSize = 0, + int NpcMidSize = 0, + int NpcBigSize = 0, + int NpcMidCutline = 0, + int NpcBigCutline = 0, + int NpcHpRegenStartTime = 0, + int NpcBossHpRegenStartTime = 0, + int NpcHpRegenPeriod = 0, + float NpcHpRegenPercent = 0f, + float NpcBossHpRegenPercent = 0f, + int NpcCombatAbandon = 0, + int BossCombatAbandon = 0, + int NpcImpossibleCombatAbandon = 0, + int MobLifeTimeExtend = 0, + float CanGetRewardDistance = 0f, + float CanGetRewardEliteDistance = 0f, + float CanGetRewardBossDistance = 0f, + int ExpLevelMaxBoundry = 0, + int CorpseHitDeadAfterCoolDown = 0, + int CorpseHitDropCoolDown = 0, + int CorpseHitDeadAfterAssistBonusCoolDown = 0, + int CorpseHitDropAssistBonusCoolDown = 0, + int UserBattleDurationTick = 0, + int RecoveryHPWaitTick = 0, + int RecoverySPWaitTick = 0, + int RecoveryEPWaitTick = 0, + int timeResetDead = 180, + int maxDeadCount = 0, + byte hitPerDeadCount = 0, + int spawntimePerDeadCount = 0, + int UserRevivalPaneltyTick = 0, + int UserRevivalPaneltyMinLevel = 0, + int revivalRate = 0, + int ChaosPointGetDefault = 0, + int ChaosPointGetPenaltyLevel = 0, + int ChaosPointGetPenalty = 0, + float FallBoundingAddedDistance = 0f, + int BoatDestinationID = 0, + int NpcKillRecoveryProbability = 0, + int InteractRemoveRetryTick = 0, + int TradeDistance = 0, + int PlayTimeDurationTick = 0, + TimeSpan DailyTrophyResetDate = new(), + float NpcLastingSightRadius = 0f, + float NpcLastingSightHeightUp = 0f, + float NpcLastingSightHeightDown = 0f, + int HoldTimeEventTick = 5000, + int OnixItemID = 0, + int BindOnixItemID = 0, + int ChaosOnixItemID = 0, + int BindChaosOnixItemID = 0, + int CrystalItemID = 0, + int ChaosCrystalItemID = 0, + int SkillChaosCrystalItemID = 0, + int RedCrystalItemID = 0, + int BlueCrystalItemID = 0, + int GreenCrystalItemID = 0, + int enchantReturnItemID = 0, + int PetCapsuleItemID = 0, + int shadowWorldBuffHpUp = 0, + int shadowWorldBuffMoveProtect = 0, + int pvpZoneUserGlobalDropID = 0, + int pvpZoneUserIndividualDropID = 0, + int pvpZoneUserDropRank = 0, + int shadowWorldUserGlobalDropID = 0, + int shadowWorldUserIndividualDropID = 0, + int shadowWorldUserDropRank = 0, + int userKillDuration = 0, + int userKillSlayerCount = 0, + int userKillRulerCount = 0, + int SystemShopNPCIDConstruct = 0, + int SystemShopNpcIDUGCDesign = 0, + int SystemShopNPCIDHonorToken = 0, + int SystemShopNPCIDFishing = 0, + int SystemShopNPCIDMentor = 0, + int SystemShopNPCIDMentee = 0, + string BlackMarketOpeningTime = "", + string BlackMarketClosingTime = "", + int BlackMarketCollectWaitSecond = 0, + int GmGlideSkillID = 0, + int normalChannelMin = 0, + int normalChannelUser = 0, + int shadowChannelMin = 0, + int shadowChannelUser = 0, + int dynamicChannelDecreaseTick = 0, + int PeriodOfMaidEmployment = 0, + int MaidReadyToPay = 0, + int MaidAffinityMax = 0, + float invokeEffectTargetCountFactor1 = 0f, + float invokeEffectTargetCountFactor2 = 0f, + float invokeEffectTargetCountFactor3 = 0f, + float invokeEffectTargetCountFactor4 = 0f, + float invokeEffectTargetCountFactor5 = 0f, + float invokeEffectTargetCountFactor6 = 0f, + float invokeEffectTargetCountFactor7 = 0f, + float invokeEffectTargetCountFactor8 = 0f, + float invokeEffectTargetCountFactor9 = 0f, + float invokeEffectTargetCountFactor10 = 0f, + int MeratRevivalDebuffCode = 0, + float MeratRevivalFeeReduceLimit = 0f, + int MeratConsumeWorldChat = 0, + int MeratConsumeChannelChat = 0, + int MeratConsumeSuperChat = 0, + int guildPVPMatchingTime = 0, + int guildPVPWinPoint = 0, + int guildPVPLosePoint = 0, + string guildPVPAdditionalEffect = "", + int ModePvPRecoverySkill = 0, + int ModePvPRecoverySP = 0, + int ModePvPInvincibleTime = 0, + int ModePVPAdditionalEffect = 0, + int ModePvPReviveBuff = 0, + int pvpBtiRewardItem = 0, + int pvpBtiRewardWinnerCount = 0, + int pvpBtiRewardLoserCount = 0, + int PvpGuildRewardItem = 0, + int PvpGuildRewardWinnerCount = 0, + int PvpGuildRewardLoserCount = 0, + string ModePVPRedArenaAdditionalEffect = "", + int ModePvPScoreDead = -50, + int ModePvPScoreKill = 100, + string ModePVPBloodMineAdditionalEffect = "", + int pvpFFAShortComboTick = 0, + int pvpFFALongComboTick = 0, + int pvpFFASlayerCount = 0, + int pvpFFARulerCount = 0, + int PvpFFAReward1Count = 0, + int PvpFFAReward2Count = 0, + int PvpFFAReward3Count = 0, + int PvpFFAReward4Count = 0, + int PvpFFAReward5Count = 0, + int PvpFFAReward6Count = 0, + int PvpFFAReward7Count = 0, + int PvpFFAReward8Count = 0, + int PvpFFAReward9Count = 0, + int PvpFFAReward10Count = 0, + int PvpFFARewardItem = 0, + int PvpFFAAdditionRewardRate = 0, + int rankDuelPvpMatchingTime = 0, + int rankDuelPvpMatchingMinGap = 0, + string ModePVPDuelRankArenaAdditionalEffect = "", + int MailExpiryDays = 0, + int MailExpiryDaysPremium = 0, + int MailExpiryDaysBlackMarket = 0, + int MailExpiryDaysFittingDoll = 0, + int decreaseMaidMoodValue = 0, + int decreaseMaidMoodMinutes = 0, + int WorldmapBossTooltipCount = 0, + int ShowNameTagEnchantItemGrade = 0, + int ShowNameTagEnchantLevel = 0, + int BossNotifyAbsLevel = 0, + int RoomExitWaitSecond = 0, + int AdditionalMesoMaxRate = 0, + int AdditionalExpMaxRate = 0, + int HonorTokenMax = 0, + int KarmaTokenMax = 0, + int LuTokenMax = 0, + int HabiTokenMax = 0, + int ReverseCoinMax = 0, + int MentorTokenMax = 0, // From KMS + int MenteeTokenMax = 0, // From KMS + int CharacterDestroyDivisionLevel = 0, + int CharacterDestroyWaitSecond = 0, + int BossShimmerScaleUpActiveDistance = 0, + float BossShimmerScaleUpSize = 0f, + float SwimDashSpeed = 0f, + int UserTriggerStateMax = 0, + int UserTriggerEnterActionMax = 0, + int UserTriggerConditionMax = 0, + int UserTriggerConditionActionMax = 0, + int PCBangAdditionalEffectID = 0, + int PCBangAdditionalEffectExp = 0, + int PCBangAdditionalEffectMeso = 0, + int PCBangItemDefaultPeriod = 0, + int ShadowWorldAutoReviveDeadAction = 0, + int GoodIteriorRecommendUICloseTime = 0, + string UGCInfoDetailViewPage = "", + int UGCInfoStoryBookID = 0, + int HomePasswordUsersKickDelay = 0, + string TriggerEditorHelpURL = "", + int partyBuffID0 = 0, + int partyBuffID1 = 0, + int returnUserPartyBuffID0 = 0, + int returnUserPartyBuffID1 = 0, + int QuestRewardSAIgnoreLevel = 0, + int ugcmapMaxUserCount = 0, + int RecallCastingTime = 0, + string RecallGuildPortalNif = "", + string RecallPartyPortalNif = "", + string RecallWeddingPortalNif = "", + int PartyRecallMerat = 0, + int RecallPortalKeepTime = 0, + int RecallPartyPortalKeepTime = 0, + float CashCallMedicLeaveDelay = 0f, + int characterSlotBaseCount = 0, + int characterSlotMaxExtraCount = 0, + int HitNPCDropCooldown = 0, + int DropSPEPBallMaxLength = 0, + int DropSPEPBallTargetZPos = 0, + int DropSPEPBallPickUpVel = 0, + int DropSPEPBallPickUpGravity = 0, + float DropSPEPBallPickUpCompleteRotateTime = 0f, + int DropSPEPBallPickUpCompleteRotateVel = 0, + int EnchantItemBindingRequireLevel = 0, + int enchantSuccessBroadcastingLevel = 0, + int EnchantEquipIngredientMaxCount = 0, + int EnchantFailStackUsingMaxCount = 0, + int EnchantFailStackTakeMaxCount = 0, + int EnchantEquipIngredientOpenLevel = 0, + int EnchantEquipIngredientOpenRank = 0, + int EnchantEquipIngredientMaxSuccessProb = 0, + int EnchantFailStackOpenLevel = 0, + int EnchantFailStackTakeMaxSuccessProb = 0, + int EnchantExpRefundMail = 0, + int BankCallDuration = 0, + string NoticeDialogUrl = "", + string NoticeDialogUrlPubTest = "", + int NoticeDialogOpenSeconds = 0, + int RemakeOptionMaxCount = 0, + int fishFightingProp = 0, + int FisherBoreDuration = 0, + string fishingStartCastingBarText0 = "", + string fishingStartCastingBarText1 = "", + string fishingStartCastingBarText2 = "", + string fishingStartCastingBarText3 = "", + string fishingStartCastingBarText4 = "", + string fishingStartBalloonText0 = "", + string fishingStartBalloonText1 = "", + string fishingStartBalloonText2 = "", + string fishingStartBalloonText3 = "", + string fishingStartBalloonText4 = "", + string fishingStartBalloonText5 = "", + string fishingStartBalloonText6 = "", + string fishingStartBalloonText7 = "", + string fishingStartBalloonText8 = "", + string fishingStartBalloonText9 = "", + string fishFightingCastingBarText0 = "", + string fishFightingBalloonText0 = "", + string fishFightingBalloonText1 = "", + string fishFightingBalloonText2 = "", + string fishFightingBalloonText3 = "", + string fishFightingBalloonText4 = "", + string fishFightingBalloonText5 = "", + int WorldmapSpecialFunctionNpcID0 = 0, + string WorldmapSpecialFunctionNpcFrame0 = "", + string WorldmapSpecialFunctionNpcTooltip0 = "", + int WorldmapSpecialFunctionNpcID1 = 0, + string WorldmapSpecialFunctionNpcFrame1 = "", + string WorldmapSpecialFunctionNpcTooltip1 = "", + int WarpOpenContinent0 = 0, + int WarpOpenContinent1 = 0, + int WarpOpenContinent2 = 0, + int WarpOpenContinent3 = 0, + string WriteMusicDetailWebPage = "", + int WriteMusicStoryBookID = 0, + int MusicListenInRadius = 0, + int MusicListenOutRadius = 0, + int MusicEnsembleRadius = 0, + int MusicEnsembleDisplayAdditionalID = 0, + int DungeonRandomMatchBuffID = 0, + int DungeonRoomMaxRewardCount = 0, + int DungeonMatchRecommendPickCount = 0, + int DungeonSeasonRankMinLevel = 0, + int ChaosDungeonReviveBossBuff = 0, + int ChaosDungeonReviveUserDebuff = 0, + int LimitMeratRevival = 0, + int MinimapScaleSkipDuration = 0, + int MinimapScaleSkipSplitPixel = 0, + int TradeMinMeso = 0, + int TradeMaxMeso = 0, + int TradeFeePercent = 0, + int GuideQuestDailyPickCountCommon = 0, + int GuideQuestDailyPickCountDungeon = 0, + int GuideQuestDailyPickCountBoss = 0, + int DailyMissionPickCount = 0, + int DailyMissionRequireLevel = 0, + float NearDropDistance =0f, + float FarDropDistance = 0f, + int MesoMarketBasePrice = 0, + int MesoMarketProductUnit0 = 0, + int MesoMarketProductUnit1 = 0, + int MesoMarketProductUnit2 = 0, + int MesoMarketProductUnit3 = 0, + int MesoMarketProductUnit4 = 0, + int MesoMarketProductUnit5 = 0, + int MesoMarketProductUnit6 = 0, + int MesoMarketProductUnit7 = 0, + int MesoMarketProductUnit8 = 0, + int MesoMarketProductUnit9 = 0, + int MesoMarketBuyPayType = 0, + int MesoMarketIconType = 0, + string MesoMarketTokenDetailUrl = "", + int BeautyHairShopGotoFieldID = 0, + int BeautyHairShopGotoPortalID = 0, + int BeautyColorShopGotoFieldID = 0, + int BeautyColorShopGotoPortalID = 0, + int BeautyFaceShopGotoFieldID = 0, + int BeautyFaceShopGotoPortalID = 0, + int DropItemSendMail = 0, + int BeautyStyleExpandSlotPrice = 0, + int BeautyStyleMaxSlotCount = 0, + int BeautyStyleDefaultSlotCount = 0, + int BeautyStyleExpandSlotCount1time = 0, + int LuckyBagCouponItemID = 0, + string CashshopFigureAddressPage = "", + string TencentCashChargeWebPage = "", + int TencentCashChargeWebPageWidth = 0, + int TencentCashChargeWebPageHight = 0, + int NxaCashChargeWebPageWidth = 0, + int NxaCashChargeWebPageHeight = 0, + int ItemUnLockTime = 0, + int PropertyProtectionTime = 0, + string TencentSecurityWebPage = "", + int HomeBankCallDuration = 0, + int HomeBankCallCooltime = 0, + string HomeBankCallSequence = "", + int HomeDoctorCallDuration = 0, + int HomeDoctorCallCooltime = 0, + string HomeDoctorCallSequence = "", + int HomeDoctorNpcID = 0, + int HomeDoctorScriptID0 = 0, + int HomeDoctorScriptID1 = 0, + int EnchantMasterScriptID = 0, + int RestExpAcquireRate = 0, + int RestExpMaxAcquireRate = 0, + int ApartmentPreviewRequireLevel = 0, + int ApartmentPreviewRequireQuestID = 0, + int CharacterAbilityDefaultPoint = 0, + int CharacterAbilityResetCoolTimeMinute = 0, + int CharacterAbilityResetMeso = 0, + int CharacterAbilityResetMerat = 0, + int CharacterAbilityOpenQuestID = 0, + int KeyboardGuideShowLevel = 0, + int extendAutoFishMaxCount = 0, + int extendAutoPlayInstrumentMaxCount = 0, + int ResetShadowBuffMerat = 0, + int InventoryExpandPrice1Row = 0, + int VIPServicePeriodLimitDay = 0, + int VIPMarketCommissionSale = 0, + int DungeonMatchNormalTimeOutTick = 0, + int ChaosDungeonHallFieldID = 0, + int ReverseRaidDungeonHallFieldID = 0, + int LapentaDungeonHallFieldID = 0, + int ColosseumDungeonHallFieldID = 0, + int BreedDuration = 0, + int HarvestDuration = 0, + int DungeonRewardUnLimitedMesoPercent = 0, + int DungeonRewardUnLimitedExpPercent = 0, + int RestartQuestStartField = 0, + int RestartQuestStartFieldRuneBlader = 0, + int RestartQuestStartFieldStriker = 0, + int RestartQuestStartFieldSoulBinder = 0, + int QuestPortalKeepTime = 0, + string QuestPortalKeepNif = "", + int QuestPortalDimensionY = 0, + int QuestPortalDimensionZ = 0, + int QuestPortalSummonTime = 0, + int QuestPortalDistanceFromNpc = 0, + int PetChangeNameMerat = 0, + int ConstructAuthorityMax = 0, + int HonorTokenResetDayOfWeek = 0, + int HonorTokenResetTimeHour = 0, + int PetLastAttackSkillCheckTick = 0, + string PetBattleAiPath = "", + int PetRunSpeed = 0, + int PetUpdateTargetInterval = 0, + int PetPickDistance = 0, + int PetSummonCastTime = 0, + int PetBoreTime = 0, + int PetIdleTime = 0, + int PetTiredTime = 0, + int PetSkillTime = 0, + string PetEffectUse = "", + string PetEffectSkill = "", + string PetEffectHappy = "", + string PetGemChatBalloon = "", + int PetTrapAreaDistanceEasy = 0, + int PetTrapAreaDistanceNormal = 0, + int PetTrapAreaDistanceHard = 0, + string PetTrapAreaEffectEasy = "", + string PetTrapAreaEffectNormal = "", + string PetTrapAreaEffectHard = "", + string PetTrapAreaEffectOtherUser = "", + string PetTamingMaxPointEffect = "", + string PetTamingAttackMissEffect = "", + string PetTrapDropItemEffect = "", + float TamingPetEscapeRate = 0f, + int TamingPetEscapeTime = 0, + int TamingPetMaxPoint = 0, + float TamingPetValidDistance = 0f, + int PetNameLengthMin = 0, + int PetNameLengthMax = 0, + int PetTrapDropVisibleDelay = 0, + int PetMaxLevel = 0, + string VisitorBookURL = "", + int bagSlotTabGameCount = 0, + int bagSlotTabSkinCount = 0, + int bagSlotTabSummonCount = 0, + int bagSlotTabMaterialCount = 0, + int bagSlotTabMasteryCount = 0, + int bagSlotTabLifeCount = 0, + int bagSlotTabQuestCount = 0, + int bagSlotTabGemCount = 0, + int bagSlotTabPetCount = 0, + int bagSlotTabActiveSkillCount = 0, + int bagSlotTabCoinCount = 0, + int bagSlotTabBadgeCount = 0, + int bagSlotTabMiscCount = 0, + int bagSlotTabLapenShardCount = 0, + int bagSlotTabPieceCount = 0, + int MasteryObjectInteractionDistance = 0, + float GatheringObjectMarkOffsetX = 0f, + float GatheringObjectMarkOffsetY = 0f, + float BreedingObjectMarkOffsetX = 0f, + float BreedingObjectMarkOffsetY = 0f, + int UGCAttention = 0, + int UGCInfringementCenter = 0, + string CharacterSelectBoreIdleEffect_Ranger = "", + string CharacterSelectBoreIdleEffect_SoulBinder = "", + int DisableSoloPlayHighLevelDungeon = 0, + int DungeonMatchCooldownTime = 0, + int DungeonUnitedRewardCountResetLevel = 0, + int MergeSmithScriptID = 0, + int AutoPressActionKeyDuration = 0, + int WebBrowserSizeWidthMin = 0, + int WebBrowserSizeWidthMax = 0, + int WebBrowserSizeHeightMin = 0, + int WebBrowserSizeHeightMax = 0, + bool WebBrowserEnableSizingButton = false, + string LiveBroadcastURL = "", + string TencentWebURL = "", + int SeasonDataSpareCount = 0, + int WebBrowserPopupSizeWidthMin = 0, + int WebBrowserPopupSizeWidthMax = 0, + int WebBrowserPopupSizeHeightMin = 0, + int WebBrowserPopupSizeHeightMax = 0, + int GlobalPortalMinLevel = 0, + int userMassiveExtraRewardMax = 0, + int SkillBookTreeAddTabFeeMerat = 0, + int MentorRequireLevel = 0, + int MenteeRequireLevel = 0, + int MentorMaxWaitingCount = 0, + int MenteeMaxReceivedCount = 0, + int CoupleEffectCheckTick = 0, + int CoupleEffectCheckRadius = 0, + int FameContentsSkyFortressMapID0 = 0, + int FameContentsSkyFortressMapID1 = 0, + int FameContentsSkyFortressMapID2 = 0, + int FameContentsSkyFortressMapID3 = 0, + int AllianceQuestPickCount = 0, + int FieldQuestPickCount = 0, + int FameContentsSkyFortressGotoMapID = 0, + int FameContentsSkyFortressGotoPortalID = 0, + int FameContentsSkyFortressBridgeID = 0, + int FameContentsMissionAttackCount = 0, + int FameContentsFieldQuestPickAccept = 0, + int FameContentsFieldQuestPickComplete = 0, + int DailyPetEnchantMaxCount = 0, + int MouseCursorHideTime = 0, + int EnchantTransformScriptID = 0, + float AutoHideGroupAlpha = 0f, + int AutoHideGroupHitVisibleTick = 0, + int UgcShopCharRotateStartDegreeY = 0, + int UgcShopCharRotateEndDegreeY = 0, + int TreeWateringEmotion = 0, + string ShopProbInfoUrl = "", + int AdventureLevelLimit = 0, + int AdventureLevelLvUpExp = 0, + int AdventureLevelMaxExp = 0, + float AdventureLevelFactor = 0f, + int AdventureExpFactorElite = 0, + int AdventureExpFactorBoss = 0, + int AdventureLevelStartLevel = 0, + int AdventureLevelLvUpRewardItem = 0, + int NameColorDeadDuration = 0, + int ConstructExpMaxCount = 0, + float MesoRevivalFeeReduceLimit = 0f, + float IngredientFeeReduceLimit = 0f, + int StatPointLimit_str = 0, + int StatPointLimit_dex = 0, + int StatPointLimit_int = 0, + int StatPointLimit_luk = 0, + int StatPointLimit_hp = 0, + int StatPointLimit_cap = 0, + float GamePadRumbleMultiple = 0f, + int WorldChampionRewardDays = 0, + int NurturingEatMaxCount = 0, + int NurturingPlayMaxCount = 0, + string NurturingQuestTag = "", + int NurturingDuration = 0, + int NurturingInteractionDistance = 0, + int NurturingEatGrowth = 0, + int NurturingPlayGrowth = 0, + int NurturingPlayMailId = 0, + int NurturingPlayMaxGrowth = 0, + int NurturingHungryTime = 0, + int SkillPointLimitLevel1 = 0, + int SkillPointLimitLevel2 = 0, + int SellPriceNormalMax = 0, + int SellPriceRareMax = 0, + int SellPriceEliteMax = 0, + int SellPriceExcellentMax = 0, + int SellPriceLegendaryMax = 0, + int SellPriceArtifactMax = 0, + string RegionServerUrl_de = "", + string RegionServerUrl_en = "", + string RegionServerUrl_bpo = "", + int TooltipLabelMaxWidth = 0, + int ClubNameLengthMin = 0, + int ClubNameLengthMax = 0, + int UgcNameLengthMin = 0, + int UgcNameLengthMax = 0, + int UgcTagLengthMax = 0, + int ChangeJobLevel = 0, + int LapenShardOpenQuestID = 0, + int MaidNameLengthMin = 0, + int MaidNameLengthMax = 0, + int MaidDescLengthMin = 0, + int MaidDescLengthMax = 0, + int GamePadStickMoveValue = 0, + int HighlightMenuUsingLevel = 0, + int PartyVoteReadyDurationSeconds = 0, + int PartyVoteReadyTagExpireSeconds = 0, + int ShieldBarOffsetY = 0, + int MouseInteractLimitDistance = 0, + int AutoInstallEquipmentMinLevel = 0, + int AutoInstallEquipmentMaxLevel = 0, + string PartySearchRegisterComboValues = "", + int FieldWarInstanceEnterableDurationSeconds = 0, + int FieldWarRequirePlayerCount = 0, + int FieldWarRequireAchieveID = 0, + int FieldWarRequireLevel = 0, + int StatScaleMarkingAdditionalEffect = 0, + string DungeonRewardFailEmotions = "", + int SummonPetSkillID = 0, + int UGCMapSetItemEffectCountLimit = 0, + int AdventureLevelMissionResetWeekday = 0, + int ItemBoxMultiOpenMaxCount = 0, + int ItemBoxMultiOpenLimitCount = 0, + int BuffBalloonDistance = 0, + int PaybackStartDate = 0, + int PaybackSettleMinutes = 0, + int PaybackMarketProductSnList = 0, + int PaybackMailId = 0, + int PaybackMailPeriodDay = 0, + int PaybackMaxRewardMerat = 0, + string PaybackGuideUrl = "", + DateTime PaybackEndDate = default, + int WeddingProposeItemID = 0, + int WeddingInvitationMaxCount = 0, + int WeddingProposeCooltime = 0, + int WeddingDivorceFieldID = 0, + int WeddingInvitationMeso = 0, + int WeddingDivorceMeso = 0, + int WeddingCoolingOffDay = 0, + int WeddingPromiseLimitDay = 0, + int WeddingHallModifyLimitHour = 0, + int WeddingDivorceRequireMarriageDay = 0, + int AdventureProtectRequireLevel = 0, + int AdventureProtectRequireQuest = 0, + int AdventureProtectCharCreateTime = 0, + int PvpOnePunchReward1Count = 0, + int PvpOnePunchReward2Count = 0, + int PvpOnePunchReward3Count = 0, + int PvpOnePunchReward4Count = 0, + int PvpOnePunchReward5Count = 0, + int PvpOnePunchReward6Count = 0, + int PvpOnePunchReward7Count = 0, + int PvpOnePunchReward8Count = 0, + int PvpOnePunchReward9Count = 0, + int PvpOnePunchReward10Count = 0, + int PvpOnePunchRewardItem = 0, + int PvpOnePunchScoreNpcKill = 0, + int SpecialHairShopID = 0, + string GemStoneProbList = "", + string SkinGemStoneProbList = "", + string PersonalInfoAgreementURL = "", + float BothHandLowDamageRatio = 0f, + float BothHandWeaponDamagePenaltyDiv = 0f, + float BothHandGearScorePenaltyDiv = 0f, + string TencentUserConsultationWebPage = "", + string TencentPricavyGuideWebPage = "", + string TencentThirdPartyInformationSharingListWebPage = "", + int PvpOnePunchUserOpenRewardItem = 0, + string TencentCharacterCreateShutdownLeft = "", + string TencentCharacterCreateShutdownRight = "", + int LeadSkillMaxSlot = 0, + int NextStateTriggerDefaultTick = 0 +); diff --git a/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs b/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs index d2ba0c346..b1c20182b 100644 --- a/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs +++ b/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs @@ -33,7 +33,8 @@ protected override void TaskResumed() { return; } - const float maxDistance = Constant.TalkableDistance * Constant.TalkableDistance; + float maxDistance = player.Session.ServerTableMetadata.ConstantsTable.Constants.TalkableDistance * + player.Session.ServerTableMetadata.ConstantsTable.Constants.TalkableDistance; // find nearest npc FieldNpc? closestNpc = player.Field.Npcs.Values From e11eec41b8b95a51e6eb1ab76581e8911cc2a66f Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Mon, 23 Feb 2026 16:45:35 -0600 Subject: [PATCH 03/26] Continue switching hard coded constants to server constants parsed during file ingest WIP --- .../Mapper/ServerTableMapper.cs | 6 ++--- Maple2.Model/Game/Cube/Nurturing.cs | 10 +++---- Maple2.Model/Game/Mail.cs | 5 ++-- Maple2.Model/Game/User/StatAttributes.cs | 26 ++++++++++--------- .../Metadata/ServerTable/ConstantsTable.cs | 6 ++--- Maple2.Server.Game/Manager/ConfigManager.cs | 19 +++++++++++--- .../MovementState.CleanupTask.cs | 4 +-- .../PacketHandlers/FunctionCubeHandler.cs | 9 ++++--- 8 files changed, 48 insertions(+), 37 deletions(-) diff --git a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs index d9af81fd0..a90687aa7 100644 --- a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs +++ b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs @@ -2114,15 +2114,15 @@ void AddSpecial(Dictionary values, Dictionary= NurturingMetadata.RequiredGrowth.Last().Exp) { return; } - Exp += Constant.NurturingEatGrowth; + Exp += nurturingEatGrowth; if (Exp >= NurturingMetadata.RequiredGrowth.First(x => x.Stage == Stage).Exp) { Stage++; } LastFeedTime = DateTimeOffset.Now; } - public bool Play(long accountId) { - if (PlayedBy.Count >= Constant.NurturingPlayMaxCount) { + public bool Play(long accountId, int nurturingEatGrowth, int nurturingPlayMaxCount) { + if (PlayedBy.Count >= nurturingPlayMaxCount) { return false; } @@ -70,7 +70,7 @@ public bool Play(long accountId) { } PlayedBy.Add(accountId); - Feed(); + Feed(nurturingEatGrowth); return true; } diff --git a/Maple2.Model/Game/Mail.cs b/Maple2.Model/Game/Mail.cs index e97dc99a8..29b3385af 100644 --- a/Maple2.Model/Game/Mail.cs +++ b/Maple2.Model/Game/Mail.cs @@ -1,6 +1,5 @@ using System.Text; using Maple2.Model.Enum; -using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Tools; using Maple2.Tools.Extensions; @@ -35,11 +34,11 @@ public class Mail : IByteSerializable { // More than 1 item may not display properly public readonly IList Items; - public Mail() { + public Mail(int mailExpiryDays) { TitleArgs = new List<(string Key, string Value)>(); ContentArgs = new List<(string Key, string Value)>(); Items = new List(); - ExpiryTime = DateTimeOffset.UtcNow.AddDays(Constant.MailExpiryDays).ToUnixTimeSeconds(); + ExpiryTime = DateTimeOffset.UtcNow.AddDays(mailExpiryDays).ToUnixTimeSeconds(); } public void Update(Mail other) { diff --git a/Maple2.Model/Game/User/StatAttributes.cs b/Maple2.Model/Game/User/StatAttributes.cs index 28cf8c61f..9c432db3a 100644 --- a/Maple2.Model/Game/User/StatAttributes.cs +++ b/Maple2.Model/Game/User/StatAttributes.cs @@ -13,9 +13,9 @@ public class StatAttributes : IByteSerializable { public int TotalPoints => Sources.Count; public int UsedPoints => Allocation.Count; - public StatAttributes() { + public StatAttributes(IDictionary statLimits) { Sources = new PointSources(); - Allocation = new PointAllocation(); + Allocation = new PointAllocation(statLimits); } public void WriteTo(IByteWriter writer) { @@ -52,6 +52,7 @@ public void WriteTo(IByteWriter writer) { public class PointAllocation : IByteSerializable { private readonly Dictionary points; + private readonly IDictionary statLimits; public BasicAttribute[] Attributes => points.Keys.ToArray(); public int Count => points.Values.Sum(); @@ -59,7 +60,7 @@ public class PointAllocation : IByteSerializable { public int this[BasicAttribute type] { get => points.GetValueOrDefault(type); set { - if (value < 0 || value > StatLimit(type)) { + if (value < 0 || value > StatLimit(type, statLimits)) { return; } if (value == 0) { @@ -71,19 +72,20 @@ public int this[BasicAttribute type] { } } - public PointAllocation() { + public PointAllocation(IDictionary statLimits) { points = new Dictionary(); + this.statLimits = statLimits; } - public static int StatLimit(BasicAttribute type) { + public static int StatLimit(BasicAttribute type, IDictionary statLimits) { return type switch { - BasicAttribute.Strength => Constant.StatPointLimit_str, - BasicAttribute.Dexterity => Constant.StatPointLimit_dex, - BasicAttribute.Intelligence => Constant.StatPointLimit_int, - BasicAttribute.Luck => Constant.StatPointLimit_luk, - BasicAttribute.Health => Constant.StatPointLimit_hp, - BasicAttribute.CriticalRate => Constant.StatPointLimit_cap, - _ => 0, + BasicAttribute.Strength => statLimits.GetValueOrDefault("StatPointLimit_str"), + BasicAttribute.Dexterity => statLimits.GetValueOrDefault("StatPointLimit_dex"), + BasicAttribute.Intelligence => statLimits.GetValueOrDefault("StatPointLimit_int"), + BasicAttribute.Luck => statLimits.GetValueOrDefault("StatPointLimit_luk"), + BasicAttribute.Health => statLimits.GetValueOrDefault("StatPointLimit_hp"), + BasicAttribute.CriticalRate => statLimits.GetValueOrDefault("StatPointLimit_cap"), + _ => 0 }; } diff --git a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs index 1f056e34c..3ee89be95 100644 --- a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs +++ b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs @@ -1,8 +1,6 @@ namespace Maple2.Model.Metadata; -public record ConstantsTable(Constants Constants) : ServerTable; - -public record Constants( +public record ConstantsTable( float NPCColorScale = 0f, float NPCDuration = 0f, float PCColorScale = 0f, @@ -866,4 +864,4 @@ public record Constants( string TencentCharacterCreateShutdownRight = "", int LeadSkillMaxSlot = 0, int NextStateTriggerDefaultTick = 0 -); +) : ServerTable; diff --git a/Maple2.Server.Game/Manager/ConfigManager.cs b/Maple2.Server.Game/Manager/ConfigManager.cs index 84a83e35b..bfe26ea37 100644 --- a/Maple2.Server.Game/Manager/ConfigManager.cs +++ b/Maple2.Server.Game/Manager/ConfigManager.cs @@ -27,6 +27,8 @@ public class ConfigManager { private readonly IList favoriteDesigners; private readonly IDictionary lapenshards; private readonly IDictionary skillCooldowns; + private readonly IDictionary statLimits; + public long DeathPenaltyEndTick { get => session.Player.Value.Character.DeathTick; private set => session.Player.Value.Character.DeathTick = value; @@ -94,7 +96,16 @@ public ConfigManager(GameStorage.Request db, GameSession session) { skillPoints = load.SkillPoint ?? new SkillPoint(); ExplorationProgress = load.ExplorationProgress; - statAttributes = new StatAttributes(); + statLimits = new Dictionary() { + { "StatPointLimit_str", session.ServerTableMetadata.ConstantsTable.StatPointLimit_str }, + { "StatPointLimit_dex", session.ServerTableMetadata.ConstantsTable.StatPointLimit_dex }, + { "StatPointLimit_int", session.ServerTableMetadata.ConstantsTable.StatPointLimit_int }, + { "StatPointLimit_luk", session.ServerTableMetadata.ConstantsTable.StatPointLimit_luk }, + { "StatPointLimit_hp", session.ServerTableMetadata.ConstantsTable.StatPointLimit_hp }, + { "StatPointLimit_cap", session.ServerTableMetadata.ConstantsTable.StatPointLimit_cap } + }; + + statAttributes = new StatAttributes(statLimits); if (load.StatPoints != null) { foreach ((AttributePointSource source, int amount) in load.StatPoints) { if (source == AttributePointSource.Prestige) { @@ -325,7 +336,7 @@ public void LoadRevival() { /// The tick when the penalty ends, or 0 to reset public void UpdateDeathPenalty(long endTick) { // Skip penalty for low level players - if (session.Player.Value.Character.Level < Constant.UserRevivalPaneltyMinLevel) { + if (session.Player.Value.Character.Level < session.ServerTableMetadata.ConstantsTable.UserRevivalPaneltyMinLevel) { return; } @@ -422,7 +433,7 @@ public bool TryGetWardrobe(int index, [NotNullWhen(true)] out Wardrobe? wardrobe #region StatPoints public void AllocateStatPoint(BasicAttribute type) { // Invalid stat type. - if (StatAttributes.PointAllocation.StatLimit(type) <= 0) { + if (StatAttributes.PointAllocation.StatLimit(type, statLimits) <= 0) { return; } @@ -432,7 +443,7 @@ public void AllocateStatPoint(BasicAttribute type) { } // Reached limit for allocation. - if (session.Config.statAttributes.Allocation[type] >= StatAttributes.PointAllocation.StatLimit(type)) { + if (session.Config.statAttributes.Allocation[type] >= StatAttributes.PointAllocation.StatLimit(type, statLimits)) { session.Send(NoticePacket.Message("s_char_info_limit_stat_point")); return; } diff --git a/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs b/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs index b1c20182b..7ef651123 100644 --- a/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs +++ b/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs @@ -33,8 +33,8 @@ protected override void TaskResumed() { return; } - float maxDistance = player.Session.ServerTableMetadata.ConstantsTable.Constants.TalkableDistance * - player.Session.ServerTableMetadata.ConstantsTable.Constants.TalkableDistance; + float maxDistance = player.Session.ServerTableMetadata.ConstantsTable.TalkableDistance * + player.Session.ServerTableMetadata.ConstantsTable.TalkableDistance; // find nearest npc FieldNpc? closestNpc = player.Field.Npcs.Values diff --git a/Maple2.Server.Game/PacketHandlers/FunctionCubeHandler.cs b/Maple2.Server.Game/PacketHandlers/FunctionCubeHandler.cs index 0ea79dfe6..8bc5ae575 100644 --- a/Maple2.Server.Game/PacketHandlers/FunctionCubeHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/FunctionCubeHandler.cs @@ -17,6 +17,7 @@ public class FunctionCubeHandler : FieldPacketHandler { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required FunctionCubeMetadataStorage FunctionCubeMetadataStorage { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadataStorage { private get; init; } // ReSharper restore All #endregion @@ -148,7 +149,7 @@ private void HandleNurturing(GameSession session, FieldFunctionInteract fieldCub // drop the item session.Field.DropItem(fieldCube.Position, fieldCube.Rotation, rewardItem, owner: session.Player, characterId: session.CharacterId); - nurturing.Feed(); + nurturing.Feed(ServerTableMetadataStorage.ConstantsTable.NurturingEatGrowth); db.UpdateNurturing(session.AccountId, fieldCube.InteractCube); session.Field.Broadcast(FunctionCubePacket.UpdateFunctionCube(fieldCube.InteractCube)); @@ -163,12 +164,12 @@ private void HandlePlayNurturing(GameSession session, Plot plot, FieldFunctionIn return; } - if (db.CountNurturingForAccount(cube.InteractCube.Metadata.Id, session.AccountId) >= Constant.NurturingPlayMaxCount) { + if (db.CountNurturingForAccount(cube.InteractCube.Metadata.Id, session.AccountId) >= ServerTableMetadataStorage.ConstantsTable.NurturingEatMaxCount) { session.Send(NoticePacket.Message("You have already played with the maximum number of pets today. TODO: Find correct string id")); // TODO: Find correct string id return; } - if (!nurturing.Play(session.AccountId)) { + if (!nurturing.Play(session.AccountId, ServerTableMetadataStorage.ConstantsTable.NurturingEatGrowth, ServerTableMetadataStorage.ConstantsTable.NurturingEatMaxCount)) { return; } @@ -216,7 +217,7 @@ private void HandlePlayNurturing(GameSession session, Plot plot, FieldFunctionIn return null; } - var mail = new Mail { + var mail = new Mail(ServerTableMetadataStorage.ConstantsTable.MailExpiryDays) { ReceiverId = ownerId, Type = MailType.System, Content = contentId, From af10dca167ee6587e63c457b644b8e80f661200c Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Tue, 24 Feb 2026 16:59:01 -0600 Subject: [PATCH 04/26] Continue switching hard coded constants to server constants pared during file ingest #2 WIP --- Maple2.Database/Model/Mail.cs | 2 +- .../Storage/Game/GameStorage.Map.cs | 4 +- Maple2.File.Ingest/Mapper/NpcMapper.cs | 9 ++-- Maple2.Model/Game/Mail.cs | 8 ++++ Maple2.Model/Metadata/NpcMetadata.cs | 9 ++-- .../Metadata/ServerTable/ConstantsTable.cs | 30 ++++++------- Maple2.Server.Game/Commands/PlayerCommand.cs | 6 +-- .../Manager/BlackMarketManager.cs | 2 +- Maple2.Server.Game/Manager/BuddyManager.cs | 6 +-- Maple2.Server.Game/Manager/BuffManager.cs | 10 ++--- Maple2.Server.Game/Manager/CurrencyManager.cs | 42 +++++++++---------- .../Manager/ExperienceManager.cs | 19 +++++---- .../Field/FieldManager/FieldManager.State.cs | 10 +++-- .../Field/FieldManager/FieldManager.cs | 2 +- Maple2.Server.Game/Manager/FishingManager.cs | 4 +- .../Manager/ItemMergeManager.cs | 2 +- .../Manager/Items/InventoryManager.cs | 36 ++++++++-------- .../Manager/Items/StorageManager.cs | 6 +-- Maple2.Server.Game/Manager/SkillManager.cs | 4 +- Maple2.Server.Game/Manager/TradeManager.cs | 8 ++-- .../Model/Field/Actor/FieldPlayer.cs | 8 ++-- Maple2.Server.Game/Model/Field/Tombstone.cs | 3 +- .../PacketHandlers/BeautyHandler.cs | 12 +++--- .../PacketHandlers/ClubHandler.cs | 4 +- .../PacketHandlers/GuildHandler.cs | 8 ++-- .../PacketHandlers/HomeBankHandler.cs | 2 +- .../PacketHandlers/HomeDoctorHandler.cs | 2 +- .../PacketHandlers/ItemLockHandler.cs | 2 +- .../PacketHandlers/JobHandler.cs | 2 +- .../PacketHandlers/MeretMarketHandler.cs | 10 ++--- .../PacketHandlers/MesoMarketHandler.cs | 4 +- .../PacketHandlers/NpcTalkHandler.cs | 2 +- .../PacketHandlers/PartyHandler.cs | 6 ++- .../PacketHandlers/QuestHandler.cs | 4 +- .../PacketHandlers/SystemShopHandler.cs | 10 ++--- .../PacketHandlers/UserChatHandler.cs | 4 +- Maple2.Server.Game/Session/GameSession.cs | 4 +- Maple2.Server.Game/Util/ChatUtil.cs | 2 +- .../CharacterManagementHandler.cs | 13 +++--- Maple2.Server.World/WorldServer.cs | 4 +- 40 files changed, 172 insertions(+), 153 deletions(-) diff --git a/Maple2.Database/Model/Mail.cs b/Maple2.Database/Model/Mail.cs index cfca17f25..0927f3107 100644 --- a/Maple2.Database/Model/Mail.cs +++ b/Maple2.Database/Model/Mail.cs @@ -55,7 +55,7 @@ internal class Mail { [return: NotNullIfNotNull(nameof(other))] public static implicit operator Maple2.Model.Game.Mail?(Mail? other) { - return other == null ? null : new Maple2.Model.Game.Mail { + return other == null ? null : new Maple2.Model.Game.Mail() { ReceiverId = other.ReceiverId, Id = other.Id, SenderId = other.SenderId, diff --git a/Maple2.Database/Storage/Game/GameStorage.Map.cs b/Maple2.Database/Storage/Game/GameStorage.Map.cs index 0ccfb0e43..37cb8cdfc 100644 --- a/Maple2.Database/Storage/Game/GameStorage.Map.cs +++ b/Maple2.Database/Storage/Game/GameStorage.Map.cs @@ -111,11 +111,11 @@ public IList LoadCubesForOwner(long ownerId) { return Context.TrySaveChanges() ? ToPlotInfo(model) : null; } - public PlotInfo? GetSoonestPlotFromExpire() { + public PlotInfo? GetSoonestPlotFromExpire(TimeSpan ugcHomeSaleWaitingTime) { IQueryable maps = Context.UgcMap.Where(map => map.ExpiryTime > DateTimeOffset.MinValue && !map.Indoor); foreach (UgcMap map in maps) { if (map.OwnerId == 0) { - map.ExpiryTime = map.ExpiryTime.Add(Constant.UgcHomeSaleWaitingTime); + map.ExpiryTime = map.ExpiryTime.Add(ugcHomeSaleWaitingTime); } } UgcMap? model = maps.OrderBy(map => map.ExpiryTime).FirstOrDefault(); diff --git a/Maple2.File.Ingest/Mapper/NpcMapper.cs b/Maple2.File.Ingest/Mapper/NpcMapper.cs index 9b7d7014f..f0871acd6 100644 --- a/Maple2.File.Ingest/Mapper/NpcMapper.cs +++ b/Maple2.File.Ingest/Mapper/NpcMapper.cs @@ -34,10 +34,11 @@ protected override IEnumerable Map() { Avoid: data.distance.avoid, Sight: data.distance.sight, SightHeightUp: data.distance.sightHeightUP, - SightHeightDown: data.distance.sightHeightDown, - LastSightRadius: data.distance.customLastSightRadius == 0 ? Constant.NpcLastSightRadius : data.distance.customLastSightRadius, - LastSightHeightUp: data.distance.customLastSightHeightUp == 0 ? Constant.NpcLastSightHeightUp : data.distance.customLastSightHeightUp, - LastSightHeightDown: data.distance.customLastSightHeightDown == 0 ? Constant.NpcLastSightHeightDown : data.distance.customLastSightHeightDown + SightHeightDown: data.distance.sightHeightDown + // TODO: Need to move to runtime due to server table constants being used as default value + //LastSightRadius: data.distance.customLastSightRadius == 0 ? Constant.NpcLastSightRadius : data.distance.customLastSightRadius, + //LastSightHeightUp: data.distance.customLastSightHeightUp == 0 ? Constant.NpcLastSightHeightUp : data.distance.customLastSightHeightUp, + //LastSightHeightDown: data.distance.customLastSightHeightDown == 0 ? Constant.NpcLastSightHeightDown : data.distance.customLastSightHeightDown ), Skill: new NpcMetadataSkill( Entries: data.skill.ids.Select((skillId, i) => diff --git a/Maple2.Model/Game/Mail.cs b/Maple2.Model/Game/Mail.cs index 29b3385af..ec1faaee4 100644 --- a/Maple2.Model/Game/Mail.cs +++ b/Maple2.Model/Game/Mail.cs @@ -34,6 +34,14 @@ public class Mail : IByteSerializable { // More than 1 item may not display properly public readonly IList Items; + // Specifically for Mail object cloning (Mail.cs:57) + public Mail() { + TitleArgs = new List<(string Key, string Value)>(); + ContentArgs = new List<(string Key, string Value)>(); + Items = new List(); + // ExpiryTime will be overwritten, no need to set it here with a parameter passing server constant value. + } + public Mail(int mailExpiryDays) { TitleArgs = new List<(string Key, string Value)>(); ContentArgs = new List<(string Key, string Value)>(); diff --git a/Maple2.Model/Metadata/NpcMetadata.cs b/Maple2.Model/Metadata/NpcMetadata.cs index db0e23db2..86ecf2af5 100644 --- a/Maple2.Model/Metadata/NpcMetadata.cs +++ b/Maple2.Model/Metadata/NpcMetadata.cs @@ -34,10 +34,11 @@ public record NpcMetadataDistance( float Avoid, float Sight, float SightHeightUp, - float SightHeightDown, - float LastSightRadius, - float LastSightHeightUp, - float LastSightHeightDown); + float SightHeightDown + // TODO: Need to move to runtime due to server table constants being used as default value + /* float LastSightRadius, + float LastSightHeightUp, + float LastSightHeightDown*/); public record NpcMetadataSkill( NpcMetadataSkill.Entry[] Entries, diff --git a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs index 3ee89be95..edb544f78 100644 --- a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs +++ b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs @@ -671,21 +671,21 @@ public record ConstantsTable( int PetTrapDropVisibleDelay = 0, int PetMaxLevel = 0, string VisitorBookURL = "", - int bagSlotTabGameCount = 0, - int bagSlotTabSkinCount = 0, - int bagSlotTabSummonCount = 0, - int bagSlotTabMaterialCount = 0, - int bagSlotTabMasteryCount = 0, - int bagSlotTabLifeCount = 0, - int bagSlotTabQuestCount = 0, - int bagSlotTabGemCount = 0, - int bagSlotTabPetCount = 0, - int bagSlotTabActiveSkillCount = 0, - int bagSlotTabCoinCount = 0, - int bagSlotTabBadgeCount = 0, - int bagSlotTabMiscCount = 0, - int bagSlotTabLapenShardCount = 0, - int bagSlotTabPieceCount = 0, + short bagSlotTabGameCount = 0, + short bagSlotTabSkinCount = 0, + short bagSlotTabSummonCount = 0, + short bagSlotTabMaterialCount = 0, + short bagSlotTabMasteryCount = 0, + short bagSlotTabLifeCount = 0, + short bagSlotTabQuestCount = 0, + short bagSlotTabGemCount = 0, + short bagSlotTabPetCount = 0, + short bagSlotTabActiveSkillCount = 0, + short bagSlotTabCoinCount = 0, + short bagSlotTabBadgeCount = 0, + short bagSlotTabMiscCount = 0, + short bagSlotTabLapenShardCount = 0, + short bagSlotTabPieceCount = 0, int MasteryObjectInteractionDistance = 0, float GatheringObjectMarkOffsetX = 0f, float GatheringObjectMarkOffsetY = 0f, diff --git a/Maple2.Server.Game/Commands/PlayerCommand.cs b/Maple2.Server.Game/Commands/PlayerCommand.cs index c1207348a..ff4f419d6 100644 --- a/Maple2.Server.Game/Commands/PlayerCommand.cs +++ b/Maple2.Server.Game/Commands/PlayerCommand.cs @@ -191,8 +191,8 @@ public PrestigeCommand(GameSession session) : base("prestige", "Sets prestige le private void Handle(InvocationContext ctx, int level) { try { - if (level is < 1 or > Constant.AdventureLevelLimit) { - ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {Constant.AdventureLevelLimit}."); + if (level < 1 || level > session.ServerTableMetadata.ConstantsTable.AdventureLevelLimit) { + ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {session.ServerTableMetadata.ConstantsTable.AdventureLevelLimit}."); return; } @@ -328,7 +328,7 @@ private void JobAdvance(Job job) { session.Player.Buffs.Clear(); session.Player.Buffs.Initialize(); - session.Player.Buffs.LoadFieldBuffs(); + session.Player.Buffs.LoadFieldBuffs(session.ServerTableMetadata.ConstantsTable.shadowWorldBuffHpUp, session.ServerTableMetadata.ConstantsTable.shadowWorldBuffMoveProtect); session.Stats.Refresh(); session.Field?.Broadcast(JobPacket.Advance(session.Player, session.Config.Skill.SkillInfo)); } diff --git a/Maple2.Server.Game/Manager/BlackMarketManager.cs b/Maple2.Server.Game/Manager/BlackMarketManager.cs index b95252a88..5086c8a40 100644 --- a/Maple2.Server.Game/Manager/BlackMarketManager.cs +++ b/Maple2.Server.Game/Manager/BlackMarketManager.cs @@ -63,7 +63,7 @@ public void Add(long itemUid, long price, int quantity) { AccountId = session.AccountId, CharacterId = session.CharacterId, Deposit = depositFee, - ExpiryTime = DateTime.Now.AddDays(Constant.BlackMarketSellEndDay).ToEpochSeconds(), + ExpiryTime = DateTime.Now.AddDays(session.ServerTableMetadata.ConstantsTable.BlackMarketSellEndDay).ToEpochSeconds(), Price = price, Quantity = quantity, }; diff --git a/Maple2.Server.Game/Manager/BuddyManager.cs b/Maple2.Server.Game/Manager/BuddyManager.cs index c4787c0db..707d7076e 100644 --- a/Maple2.Server.Game/Manager/BuddyManager.cs +++ b/Maple2.Server.Game/Manager/BuddyManager.cs @@ -87,7 +87,7 @@ public void SendInvite(string name, string message) { session.Send(BuddyPacket.Invite(error: s_buddy_err_my_id_ex)); return; } - if (buddies.Count >= Constant.MaxBuddyCount) { + if (buddies.Count >= session.ServerTableMetadata.ConstantsTable.MaxBuddyCount) { session.Send(BuddyPacket.Invite(error: s_buddy_err_max_buddy)); return; } @@ -113,7 +113,7 @@ public void SendInvite(string name, string message) { try { db.BeginTransaction(); - if (db.CountBuddy(receiverId) >= Constant.MaxBuddyCount) { + if (db.CountBuddy(receiverId) >= session.ServerTableMetadata.ConstantsTable.MaxBuddyCount) { session.Send(BuddyPacket.Invite(name: name, error: s_buddy_err_target_full)); return; } @@ -262,7 +262,7 @@ public void SendBlock(long entryId, string name, string message) { session.Send(BuddyPacket.Block(error: s_buddy_err_unknown)); return; } - if (blocked.Count >= Constant.MaxBlockCount) { + if (blocked.Count >= session.ServerTableMetadata.ConstantsTable.MaxBlockCount) { session.Send(BuddyPacket.Block(name: name, error: s_buddy_err_max_block)); return; } diff --git a/Maple2.Server.Game/Manager/BuffManager.cs b/Maple2.Server.Game/Manager/BuffManager.cs index f9e378c22..3809822b4 100644 --- a/Maple2.Server.Game/Manager/BuffManager.cs +++ b/Maple2.Server.Game/Manager/BuffManager.cs @@ -60,11 +60,11 @@ public void Clear() { } } - public void LoadFieldBuffs() { + public void LoadFieldBuffs(int shadowWorldBuffHpUp, int shadowWorldBuffMoveProtect) { // Lapenshards // Game Events // Prestige - EnterField(); + EnterField(shadowWorldBuffHpUp, shadowWorldBuffMoveProtect); if (Actor is FieldPlayer player) { player.Session.Config.RefreshPremiumClubBuffs(); } @@ -438,7 +438,7 @@ public void LeaveField() { Remove(buffsToRemove.ToArray()); } - private void EnterField() { + private void EnterField(int shadowWorldBuffHpUp, int shadowWorldBuffMoveProtect) { foreach (MapEntranceBuff buff in Actor.Field.Metadata.EntranceBuffs) { AddBuff(Actor, Actor, buff.Id, buff.Level, Actor.Field.FieldTick); } @@ -458,8 +458,8 @@ private void EnterField() { } if (Actor.Field.Metadata.Property.Region == MapRegion.ShadowWorld) { - AddBuff(Actor, Actor, Constant.shadowWorldBuffHpUp, 1, Actor.Field.FieldTick); - AddBuff(Actor, Actor, Constant.shadowWorldBuffMoveProtect, 1, Actor.Field.FieldTick); + AddBuff(Actor, Actor, shadowWorldBuffHpUp, 1, Actor.Field.FieldTick); + AddBuff(Actor, Actor, shadowWorldBuffMoveProtect, 1, Actor.Field.FieldTick); } } diff --git a/Maple2.Server.Game/Manager/CurrencyManager.cs b/Maple2.Server.Game/Manager/CurrencyManager.cs index 09bf934c8..f056a4229 100644 --- a/Maple2.Server.Game/Manager/CurrencyManager.cs +++ b/Maple2.Server.Game/Manager/CurrencyManager.cs @@ -98,57 +98,57 @@ public long this[CurrencyType type] { long overflow; switch (type) { case CurrencyType.ValorToken: - delta = Math.Min(value, Constant.HonorTokenMax) - Currency.ValorToken; - overflow = Math.Max(0, value - Constant.HonorTokenMax); - Currency.ValorToken = Math.Min(value, Constant.HonorTokenMax); + delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.HonorTokenMax) - Currency.ValorToken; + overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.HonorTokenMax); + Currency.ValorToken = Math.Min(value, session.ServerTableMetadata.ConstantsTable.HonorTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_honor_token, delta); } break; case CurrencyType.Treva: - delta = Math.Min(value, Constant.KarmaTokenMax) - Currency.Treva; - overflow = Math.Max(0, value - Constant.KarmaTokenMax); - Currency.Treva = Math.Min(value, Constant.KarmaTokenMax); + delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.KarmaTokenMax) - Currency.Treva; + overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.KarmaTokenMax); + Currency.Treva = Math.Min(value, session.ServerTableMetadata.ConstantsTable.KarmaTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_karma_token, delta); } break; case CurrencyType.Rue: - delta = Math.Min(value, Constant.LuTokenMax) - Currency.Rue; - overflow = Math.Max(0, value - Constant.LuTokenMax); - Currency.Rue = Math.Min(value, Constant.LuTokenMax); + delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.LuTokenMax) - Currency.Rue; + overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.LuTokenMax); + Currency.Rue = Math.Min(value, session.ServerTableMetadata.ConstantsTable.LuTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_lu_token, delta); } break; case CurrencyType.HaviFruit: - delta = Math.Min(value, Constant.HaviTokenMax) - Currency.HaviFruit; - overflow = Math.Max(0, value - Constant.HaviTokenMax); - Currency.HaviFruit = Math.Min(value, Constant.HaviTokenMax); + delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.HabiTokenMax) - Currency.HaviFruit; + overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.HabiTokenMax); + Currency.HaviFruit = Math.Min(value, session.ServerTableMetadata.ConstantsTable.HabiTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_habi_token, delta); } break; case CurrencyType.ReverseCoin: - delta = Math.Min(value, Constant.ReverseCoinMax) - Currency.ReverseCoin; - overflow = Math.Max(0, value - Constant.ReverseCoinMax); - Currency.ReverseCoin = Math.Min(value, Constant.ReverseCoinMax); + delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.ReverseCoinMax) - Currency.ReverseCoin; + overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.ReverseCoinMax); + Currency.ReverseCoin = Math.Min(value, session.ServerTableMetadata.ConstantsTable.ReverseCoinMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_reverse_coin, delta); } break; case CurrencyType.MentorToken: - delta = Math.Min(value, Constant.MentorTokenMax) - Currency.MentorToken; - overflow = Math.Max(0, value - Constant.MentorTokenMax); - Currency.MentorToken = Math.Min(value, Constant.MentorTokenMax); + delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.MentorTokenMax) - Currency.MentorToken; + overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.MentorTokenMax); + Currency.MentorToken = Math.Min(value, session.ServerTableMetadata.ConstantsTable.MentorTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_mentor_token, delta); } break; case CurrencyType.MenteeToken: - delta = Math.Min(value, Constant.MenteeTokenMax) - Currency.MenteeToken; - overflow = Math.Max(0, value - Constant.MenteeTokenMax); - Currency.MenteeToken = Math.Min(value, Constant.MenteeTokenMax); + delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.MenteeTokenMax) - Currency.MenteeToken; + overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.MenteeTokenMax); + Currency.MenteeToken = Math.Min(value, session.ServerTableMetadata.ConstantsTable.MenteeTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_mentee_token, delta); } diff --git a/Maple2.Server.Game/Manager/ExperienceManager.cs b/Maple2.Server.Game/Manager/ExperienceManager.cs index 2300b62ab..e733c0dac 100644 --- a/Maple2.Server.Game/Manager/ExperienceManager.cs +++ b/Maple2.Server.Game/Manager/ExperienceManager.cs @@ -89,7 +89,7 @@ public void OnKill(IActor npc) { } private long GetRestExp(long expGained) { - long addedRestExp = Math.Min(RestExp, (long) (expGained * (Constant.RestExpAcquireRate / 10000.0f))); // convert int to a percentage + long addedRestExp = Math.Min(RestExp, (long) (expGained * (session.ServerTableMetadata.ConstantsTable.RestExpAcquireRate / 10000.0f))); // convert int to a percentage RestExp = Math.Max(0, RestExp - addedRestExp); Exp += expGained; return addedRestExp; @@ -203,7 +203,7 @@ public bool LevelUp() { } private void AddPrestigeExp(ExpType expType) { - if (Level < Constant.AdventureLevelStartLevel) { + if (Level < session.ServerTableMetadata.ConstantsTable.AdventureLevelStartLevel) { return; } @@ -211,19 +211,20 @@ private void AddPrestigeExp(ExpType expType) { return; } - if (PrestigeCurrentExp - PrestigeExp + (PrestigeLevelsGained * Constant.AdventureLevelLvUpExp) >= Constant.AdventureLevelLvUpExp) { - amount = (long) (amount * Constant.AdventureLevelFactor); + if (PrestigeCurrentExp - PrestigeExp + (PrestigeLevelsGained * session.ServerTableMetadata.ConstantsTable.AdventureLevelLvUpExp) >= + session.ServerTableMetadata.ConstantsTable.AdventureLevelLvUpExp) { + amount = (long) (amount * session.ServerTableMetadata.ConstantsTable.AdventureLevelFactor); } PrestigeCurrentExp = Math.Min(amount + PrestigeCurrentExp, long.MaxValue); int startLevel = PrestigeLevel; - for (int level = startLevel; level < Constant.AdventureLevelLimit; level++) { - if (Constant.AdventureLevelLvUpExp > PrestigeCurrentExp) { + for (int level = startLevel; level < session.ServerTableMetadata.ConstantsTable.AdventureLevelLimit; level++) { + if (session.ServerTableMetadata.ConstantsTable.AdventureLevelLvUpExp > PrestigeCurrentExp) { break; } - PrestigeCurrentExp -= Constant.AdventureLevelLvUpExp; + PrestigeCurrentExp -= session.ServerTableMetadata.ConstantsTable.AdventureLevelLvUpExp; PrestigeLevel++; } session.Send(PrestigePacket.AddExp(PrestigeCurrentExp, amount)); @@ -233,7 +234,7 @@ private void AddPrestigeExp(ExpType expType) { } public void PrestigeLevelUp(int amount = 1) { - PrestigeLevel = Math.Clamp(PrestigeLevel + amount, amount, Constant.AdventureLevelLimit); + PrestigeLevel = Math.Clamp(PrestigeLevel + amount, amount, session.ServerTableMetadata.ConstantsTable.AdventureLevelLimit); PrestigeLevelsGained += amount; session.ConditionUpdate(ConditionType.adventure_level, counter: amount); session.ConditionUpdate(ConditionType.adventure_level_up, counter: amount); @@ -242,7 +243,7 @@ public void PrestigeLevelUp(int amount = 1) { } for (int i = 0; i < amount; i++) { - Item? item = session.Field?.ItemDrop.CreateItem(Constant.AdventureLevelLvUpRewardItem); + Item? item = session.Field?.ItemDrop.CreateItem(session.ServerTableMetadata.ConstantsTable.AdventureLevelLvUpRewardItem); if (item == null) { break; } diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs index 3da48aa88..59d0d66e9 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs @@ -204,15 +204,17 @@ public FieldPortal SpawnPortal(Portal portal, int roomId, Vector3 position = def } public FieldPortal SpawnPortal(QuestSummonPortal metadata, FieldNpc npc, FieldPlayer owner) { - var portal = new Portal(NextLocalId(), metadata.MapId, metadata.PortalId, PortalType.Quest, PortalActionType.Interact, npc.Position.Offset(Constant.QuestPortalDistanceFromNpc, npc.Rotation), npc.Rotation, - new Vector3(Constant.QuestPortalDistanceFromNpc, Constant.QuestPortalDimensionY, Constant.QuestPortalDimensionZ), Constant.QuestPortalDistanceFromNpc, + var portal = new Portal(NextLocalId(), metadata.MapId, metadata.PortalId, PortalType.Quest, PortalActionType.Interact, + npc.Position.Offset(owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalDistanceFromNpc, npc.Rotation), npc.Rotation, + new Vector3(owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalDistanceFromNpc, owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalDimensionY, + owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalDimensionZ), owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalDistanceFromNpc, 0, true, false, true); var fieldPortal = new FieldQuestPortal(owner, this, NextLocalId(), portal) { Position = portal.Position, Rotation = portal.Rotation, - EndTick = (FieldTick + (long) TimeSpan.FromSeconds(Constant.QuestPortalKeepTime).TotalMilliseconds).Truncate32(), + EndTick = (FieldTick + (long) TimeSpan.FromSeconds(owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalKeepTime).TotalMilliseconds).Truncate32(), StartTick = FieldTickInt, - Model = Constant.QuestPortalKeepNif, + Model = owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalKeepNif, }; fieldPortals[fieldPortal.ObjectId] = fieldPortal; diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs index ea1983ab1..3554058de 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs @@ -355,7 +355,7 @@ public void EnsurePlayerPosition(FieldPlayer player) { return; } - player.FallDamage(Constant.FallBoundingAddedDistance); + player.FallDamage(player.Session.ServerTableMetadata.ConstantsTable.FallBoundingAddedDistance); player.MoveToPosition(player.LastGroundPosition.Align() + new Vector3(0, 0, 150f), default); } diff --git a/Maple2.Server.Game/Manager/FishingManager.cs b/Maple2.Server.Game/Manager/FishingManager.cs index aebd61425..aeffa3c3e 100644 --- a/Maple2.Server.Game/Manager/FishingManager.cs +++ b/Maple2.Server.Game/Manager/FishingManager.cs @@ -239,12 +239,12 @@ public FishingError Start(Vector3 position) { selectedFish = fishes.Get(); - int fishingTick = Constant.FisherBoreDuration; + int fishingTick = session.ServerTableMetadata.ConstantsTable.FisherBoreDuration; bool hasAutoFish = session.Player.Buffs.HasBuff(BuffEventType.AutoFish); // Fishing Success if (Random.Shared.Next(0, 10000) < selectedFish.BaitProbability) { - if (!hasAutoFish && Random.Shared.Next(0, 10000) < Constant.FishFightingProp) { + if (!hasAutoFish && Random.Shared.Next(0, 10000) < session.ServerTableMetadata.ConstantsTable.fishFightingProp) { fishFightGame = true; } diff --git a/Maple2.Server.Game/Manager/ItemMergeManager.cs b/Maple2.Server.Game/Manager/ItemMergeManager.cs index 9d2ba918f..b9c30de3e 100644 --- a/Maple2.Server.Game/Manager/ItemMergeManager.cs +++ b/Maple2.Server.Game/Manager/ItemMergeManager.cs @@ -86,7 +86,7 @@ public void SelectCrystal(long itemUid, long crystalUid) { session.Send(ItemMergePacket.Select(mergeSlot, ItemMerge.CostMultiplier(upgradeItem.Rarity))); if (!session.ScriptMetadata.TryGet(Constant.EmpowermentNpc, out ScriptMetadata? script) || - !script.States.TryGetValue(Constant.MergeSmithScriptID, out ScriptState? state)) { + !script.States.TryGetValue(session.ServerTableMetadata.ConstantsTable.MergeSmithScriptID, out ScriptState? state)) { return; } diff --git a/Maple2.Server.Game/Manager/Items/InventoryManager.cs b/Maple2.Server.Game/Manager/Items/InventoryManager.cs index 83a1c09a8..78fc94e3b 100644 --- a/Maple2.Server.Game/Manager/Items/InventoryManager.cs +++ b/Maple2.Server.Game/Manager/Items/InventoryManager.cs @@ -44,23 +44,23 @@ public InventoryManager(GameStorage.Request db, GameSession session) { } } - private static short BaseSize(InventoryType type) { + private short BaseSize(InventoryType type) { return type switch { - InventoryType.Gear => Constant.BagSlotTabGameCount, - InventoryType.Outfit => Constant.BagSlotTabSkinCount, - InventoryType.Mount => Constant.BagSlotTabSummonCount, - InventoryType.Catalyst => Constant.BagSlotTabMaterialCount, - InventoryType.FishingMusic => Constant.BagSlotTabLifeCount, - InventoryType.Quest => Constant.BagSlotTabQuestCount, - InventoryType.Gemstone => Constant.BagSlotTabGemCount, - InventoryType.Misc => Constant.BagSlotTabMiscCount, - InventoryType.LifeSkill => Constant.BagSlotTabMasteryCount, - InventoryType.Pets => Constant.BagSlotTabPetCount, - InventoryType.Consumable => Constant.BagSlotTabActiveSkillCount, - InventoryType.Currency => Constant.BagSlotTabCoinCount, - InventoryType.Badge => Constant.BagSlotTabBadgeCount, - InventoryType.Lapenshard => Constant.BagSlotTabLapenshardCount, - InventoryType.Fragment => Constant.BagSlotTabPieceCount, + InventoryType.Gear => session.ServerTableMetadata.ConstantsTable.bagSlotTabGameCount, + InventoryType.Outfit => session.ServerTableMetadata.ConstantsTable.bagSlotTabSkinCount, + InventoryType.Mount => session.ServerTableMetadata.ConstantsTable.bagSlotTabSummonCount, + InventoryType.Catalyst => session.ServerTableMetadata.ConstantsTable.bagSlotTabMaterialCount, + InventoryType.FishingMusic => session.ServerTableMetadata.ConstantsTable.bagSlotTabLifeCount, + InventoryType.Quest => session.ServerTableMetadata.ConstantsTable.bagSlotTabQuestCount, + InventoryType.Gemstone => session.ServerTableMetadata.ConstantsTable.bagSlotTabGemCount, + InventoryType.Misc => session.ServerTableMetadata.ConstantsTable.bagSlotTabMiscCount, + InventoryType.LifeSkill => session.ServerTableMetadata.ConstantsTable.bagSlotTabMasteryCount, + InventoryType.Pets => session.ServerTableMetadata.ConstantsTable.bagSlotTabPetCount, + InventoryType.Consumable => session.ServerTableMetadata.ConstantsTable.bagSlotTabActiveSkillCount, + InventoryType.Currency => session.ServerTableMetadata.ConstantsTable.bagSlotTabCoinCount, + InventoryType.Badge => session.ServerTableMetadata.ConstantsTable.bagSlotTabBadgeCount, + InventoryType.Lapenshard => session.ServerTableMetadata.ConstantsTable.bagSlotTabLapenShardCount, + InventoryType.Fragment => session.ServerTableMetadata.ConstantsTable.bagSlotTabPieceCount, _ => throw new ArgumentOutOfRangeException($"Invalid InventoryType: {type}"), }; } @@ -557,7 +557,7 @@ public bool Expand(InventoryType type, int expandRowCount = Constant.InventoryEx return false; } - if (session.Currency.Meret < Constant.InventoryExpandPrice1Row) { + if (session.Currency.Meret < session.ServerTableMetadata.ConstantsTable.InventoryExpandPrice1Row) { session.Send(ItemInventoryPacket.Error(s_cannot_charge_merat)); return false; } @@ -566,7 +566,7 @@ public bool Expand(InventoryType type, int expandRowCount = Constant.InventoryEx return false; } - session.Currency.Meret -= Constant.InventoryExpandPrice1Row; + session.Currency.Meret -= session.ServerTableMetadata.ConstantsTable.InventoryExpandPrice1Row; if (session.Player.Value.Unlock.Expand.ContainsKey(type)) { session.Player.Value.Unlock.Expand[type] = newExpand; } else { diff --git a/Maple2.Server.Game/Manager/Items/StorageManager.cs b/Maple2.Server.Game/Manager/Items/StorageManager.cs index 6ee15adf5..c38cd9a27 100644 --- a/Maple2.Server.Game/Manager/Items/StorageManager.cs +++ b/Maple2.Server.Game/Manager/Items/StorageManager.cs @@ -189,11 +189,11 @@ public void WithdrawMesos(long amount) { public void Expand() { lock (session.Item) { short newSize = (short) (items.Size + Constant.InventoryExpandRowCount); - if (newSize > Constant.StoreExpandMaxSlotCount) { + if (newSize > session.ServerTableMetadata.ConstantsTable.StoreExpandMaxSlotCount) { session.Send(StorageInventoryPacket.Error(s_store_err_expand_max)); return; } - if (session.Currency.Meret < Constant.StoreExpandPrice1Row) { + if (session.Currency.Meret < session.ServerTableMetadata.ConstantsTable.StoreExpandPrice1Row) { session.Send(StorageInventoryPacket.Error(s_cannot_charge_merat)); return; } @@ -203,7 +203,7 @@ public void Expand() { return; } - session.Currency.Meret -= Constant.StoreExpandPrice1Row; + session.Currency.Meret -= session.ServerTableMetadata.ConstantsTable.StoreExpandPrice1Row; expand += Constant.InventoryExpandRowCount; Load(); diff --git a/Maple2.Server.Game/Manager/SkillManager.cs b/Maple2.Server.Game/Manager/SkillManager.cs index 45f5c5754..19a38c285 100644 --- a/Maple2.Server.Game/Manager/SkillManager.cs +++ b/Maple2.Server.Game/Manager/SkillManager.cs @@ -121,11 +121,11 @@ public bool ExpandSkillTabs() { if (SkillBook.MaxSkillTabs >= Constant.MaxSkillTabCount) { return false; } - if (session.Currency.Meret < Constant.SkillBookTreeAddTabFeeMeret) { + if (session.Currency.Meret < session.ServerTableMetadata.ConstantsTable.SkillBookTreeAddTabFeeMerat) { return false; } - session.Currency.Meret -= Constant.SkillBookTreeAddTabFeeMeret; + session.Currency.Meret -= session.ServerTableMetadata.ConstantsTable.SkillBookTreeAddTabFeeMerat; SkillBook.MaxSkillTabs++; session.Send(SkillBookPacket.Expand(SkillBook)); diff --git a/Maple2.Server.Game/Manager/TradeManager.cs b/Maple2.Server.Game/Manager/TradeManager.cs index c356246b8..67fd0f1d9 100644 --- a/Maple2.Server.Game/Manager/TradeManager.cs +++ b/Maple2.Server.Game/Manager/TradeManager.cs @@ -34,7 +34,7 @@ public TradeManager(GameSession sender, GameSession receiver) { // End the trade if not accepted before |TradeRequestDuration|. string receiverName = receiver.Player.Value.Character.Name; Task.Factory.StartNew(() => { - Thread.Sleep(TimeSpan.FromSeconds(Constant.TradeRequestDuration)); + Thread.Sleep(TimeSpan.FromSeconds(sender.ServerTableMetadata.ConstantsTable.TradeRequestDuration)); lock (mutex) { if (state is not (TradeState.Requested or TradeState.Acknowledged)) { return; @@ -168,7 +168,7 @@ public void SetMesos(GameSession caller, long amount) { return; } - if (amount > Constant.TradeMaxMeso) { + if (amount > caller.ServerTableMetadata.ConstantsTable.TradeMaxMeso) { caller.Send(TradePacket.Error(s_trade_error_invalid_meso)); return; } @@ -247,7 +247,7 @@ private void EndTrade(bool success) { } lock (sender.Session.Item) { - long fee = success ? (long) (Constant.TradeFeePercent / 100f * sender.Mesos) : 0; + long fee = success ? (long) (sender.Session.ServerTableMetadata.ConstantsTable.TradeFeePercent / 100f * sender.Mesos) : 0; sender.Session.Currency.Meso += sender.Mesos - fee; foreach (Item item in sender.Items) { if (item.Transfer?.Flag.HasFlag(TransferFlag.LimitTrade) == true) { @@ -260,7 +260,7 @@ private void EndTrade(bool success) { sender.Clear(); } lock (receiver.Session.Item) { - long fee = success ? (long) (Constant.TradeFeePercent / 100f * receiver.Mesos) : 0; + long fee = success ? (long) (receiver.Session.ServerTableMetadata.ConstantsTable.TradeFeePercent / 100f * receiver.Mesos) : 0; receiver.Session.Currency.Meso += receiver.Mesos - fee; foreach (Item item in receiver.Items) { if (item.Transfer?.Flag.HasFlag(TransferFlag.LimitTrade) == true) { diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs b/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs index ce3b45acf..4179e9aaf 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs @@ -168,7 +168,7 @@ public override void Update(long tickCount) { return; } - if (InBattle && tickCount - battleTick > Constant.UserBattleDurationTick) { + if (InBattle && tickCount - battleTick > Session.ServerTableMetadata.ConstantsTable.UserBattleDurationTick) { InBattle = false; } @@ -402,7 +402,7 @@ public bool Revive(bool instant = false) { // Apply death penalty if field requires it if (Field.Metadata.Property.DeathPenalty) { - Session.Config.UpdateDeathPenalty(Field.FieldTick + Constant.UserRevivalPaneltyTick); + Session.Config.UpdateDeathPenalty(Field.FieldTick + Session.ServerTableMetadata.ConstantsTable.UserRevivalPaneltyTick); } // Update revival condition @@ -474,7 +474,7 @@ public void ConsumeHp(int amount) { Stat stat = Stats.Values[BasicAttribute.Health]; stat.Add(-amount); if (!IsDead) { - lastRegenTime[BasicAttribute.Health] = Field.FieldTick + Constant.RecoveryHPWaitTick; + lastRegenTime[BasicAttribute.Health] = Field.FieldTick + Session.ServerTableMetadata.ConstantsTable.RecoveryHPWaitTick; } Session.Send(StatsPacket.Update(this, BasicAttribute.Health)); @@ -547,7 +547,7 @@ public void ConsumeStamina(int amount, bool noRegen = false) { Stats.Values[BasicAttribute.Stamina].Add(-amount); if (!IsDead) { - lastRegenTime[BasicAttribute.Stamina] = Field.FieldTick + Constant.RecoveryEPWaitTick; + lastRegenTime[BasicAttribute.Stamina] = Field.FieldTick + Session.ServerTableMetadata.ConstantsTable.RecoveryEPWaitTick; } Field.Broadcast(StatsPacket.Update(this, BasicAttribute.Stamina)); } diff --git a/Maple2.Server.Game/Model/Field/Tombstone.cs b/Maple2.Server.Game/Model/Field/Tombstone.cs index 4eb54f9b7..0d0b7a488 100644 --- a/Maple2.Server.Game/Model/Field/Tombstone.cs +++ b/Maple2.Server.Game/Model/Field/Tombstone.cs @@ -26,7 +26,8 @@ public byte HitsRemaining { public Tombstone(FieldPlayer owner, int totalDeaths) { Owner = owner; - TotalHitCount = (byte) Math.Min(totalDeaths * Constant.hitPerDeadCount, Constant.hitPerDeadCount * Constant.maxDeadCount); + TotalHitCount = (byte) Math.Min(totalDeaths * owner.Session.ServerTableMetadata.ConstantsTable.hitPerDeadCount, + owner.Session.ServerTableMetadata.ConstantsTable.hitPerDeadCount * owner.Session.ServerTableMetadata.ConstantsTable.maxDeadCount); hitsRemaining = TotalHitCount; } public void WriteTo(IByteWriter writer) { diff --git a/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs b/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs index dd3a7c5e2..99cfb24c7 100644 --- a/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs @@ -351,15 +351,15 @@ private void HandleRandomHair(GameSession session, IByteReader packet) { private void HandleWarp(GameSession session, IByteReader packet) { short type = packet.ReadShort(); int mapId = type switch { - 1 => Constant.BeautyHairShopGotoFieldID, - 3 => Constant.BeautyFaceShopGotoFieldID, - 5 => Constant.BeautyColorShopGotoFieldID, + 1 => session.ServerTableMetadata.ConstantsTable.BeautyHairShopGotoFieldID, + 3 => session.ServerTableMetadata.ConstantsTable.BeautyFaceShopGotoFieldID, + 5 => session.ServerTableMetadata.ConstantsTable.BeautyColorShopGotoFieldID, _ => 0, }; int portalId = type switch { - 1 => Constant.BeautyHairShopGotoPortalID, - 3 => Constant.BeautyFaceShopGotoPortalID, - 5 => Constant.BeautyColorShopGotoPortalID, + 1 => session.ServerTableMetadata.ConstantsTable.BeautyHairShopGotoPortalID, + 3 => session.ServerTableMetadata.ConstantsTable.BeautyFaceShopGotoPortalID, + 5 => session.ServerTableMetadata.ConstantsTable.BeautyColorShopGotoPortalID, _ => 0, }; diff --git a/Maple2.Server.Game/PacketHandlers/ClubHandler.cs b/Maple2.Server.Game/PacketHandlers/ClubHandler.cs index a513f2e05..293589ef0 100644 --- a/Maple2.Server.Game/PacketHandlers/ClubHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/ClubHandler.cs @@ -71,7 +71,7 @@ private void HandleCreate(GameSession session, IByteReader packet) { session.Send(ClubPacket.Error(ClubError.s_club_err_name_value)); return; } - if (clubName.Length is < Constant.ClubNameLengthMin or > Constant.ClubNameLengthMax) { + if (clubName.Length < session.ServerTableMetadata.ConstantsTable.ClubNameLengthMin || clubName.Length > session.ServerTableMetadata.ConstantsTable.ClubNameLengthMax) { session.Send(ClubPacket.Error(ClubError.s_club_err_name_value)); return; } @@ -243,7 +243,7 @@ private void HandleRename(GameSession session, IByteReader packet) { session.Send(ClubPacket.Error(ClubError.s_club_err_name_value)); return; } - if (newName.Length is < Constant.ClubNameLengthMin or > Constant.ClubNameLengthMax) { + if (newName.Length < session.ServerTableMetadata.ConstantsTable.ClubNameLengthMin || newName.Length > session.ServerTableMetadata.ConstantsTable.ClubNameLengthMax) { session.Send(ClubPacket.Error(ClubError.s_club_err_name_value)); return; } diff --git a/Maple2.Server.Game/PacketHandlers/GuildHandler.cs b/Maple2.Server.Game/PacketHandlers/GuildHandler.cs index f54052620..8b4e124fd 100644 --- a/Maple2.Server.Game/PacketHandlers/GuildHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/GuildHandler.cs @@ -193,7 +193,7 @@ private void HandleCreate(GameSession session, IByteReader packet) { session.Send(GuildPacket.Error(GuildError.s_guild_err_name_value)); return; } - if (guildName.Length is < Constant.GuildNameLengthMin or > Constant.GuildNameLengthMax) { + if (guildName.Length < session.ServerTableMetadata.ConstantsTable.GuildNameLengthMin || guildName.Length > session.ServerTableMetadata.ConstantsTable.GuildNameLengthMax) { session.Send(GuildPacket.Error(GuildError.s_guild_err_name_value)); return; } @@ -208,11 +208,11 @@ private void HandleCreate(GameSession session, IByteReader packet) { return; } - if (session.Player.Value.Character.Level < Constant.GuildCreateMinLevel) { + if (session.Player.Value.Character.Level < session.ServerTableMetadata.ConstantsTable.GuildCreateMinLevel) { session.Send(GuildPacket.Error(GuildError.s_guild_err_not_enough_level)); return; } - if (session.Currency.CanAddMeso(-Constant.GuildCreatePrice) != -Constant.GuildCreatePrice) { + if (session.Currency.CanAddMeso(-session.ServerTableMetadata.ConstantsTable.GuildCreatePrice) != -session.ServerTableMetadata.ConstantsTable.GuildCreatePrice) { session.Send(GuildPacket.Error(GuildError.s_guild_err_no_money)); return; } @@ -236,7 +236,7 @@ private void HandleCreate(GameSession session, IByteReader packet) { } session.Guild.SetGuild(response.Guild); - session.Currency.Meso -= Constant.GuildCreatePrice; + session.Currency.Meso -= session.ServerTableMetadata.ConstantsTable.GuildCreatePrice; session.Guild.Load(); session.Send(GuildPacket.Created(guildName)); diff --git a/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs b/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs index a876688cc..5026761ba 100644 --- a/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs @@ -20,7 +20,7 @@ public override void Handle(GameSession session, IByteReader packet) { switch (command) { case Command.Home: long time = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - if (session.Player.Value.Character.StorageCooldown + Constant.HomeBankCallCooldown > time) { + if (session.Player.Value.Character.StorageCooldown + session.ServerTableMetadata.ConstantsTable.HomeBankCallCooltime > time) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs b/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs index 2b0e28e15..b306b9867 100644 --- a/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs @@ -15,7 +15,7 @@ public class HomeDoctorHandler : FieldPacketHandler { public override void Handle(GameSession session, IByteReader packet) { if (session.Field is null) return; long time = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - if (session.Player.Value.Character.DoctorCooldown + Constant.HomeDoctorCallCooldown > time) { + if (session.Player.Value.Character.DoctorCooldown + session.ServerTableMetadata.ConstantsTable.HomeDoctorCallCooltime > time) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs b/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs index aac7be7b5..ac45bf140 100644 --- a/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs @@ -86,7 +86,7 @@ private static void HandleCommit(GameSession session, IByteReader packet) { if (unlock && item.IsLocked) { item.IsLocked = false; - item.UnlockTime = DateTimeOffset.UtcNow.AddSeconds(Constant.ItemUnLockTime).ToUnixTimeSeconds(); + item.UnlockTime = DateTimeOffset.UtcNow.AddSeconds(session.ServerTableMetadata.ConstantsTable.ItemUnLockTime).ToUnixTimeSeconds(); updatedItems.Add(item); } else if (!unlock && !item.IsLocked) { item.IsLocked = true; diff --git a/Maple2.Server.Game/PacketHandlers/JobHandler.cs b/Maple2.Server.Game/PacketHandlers/JobHandler.cs index 6ba30b8ca..0e0b720bd 100644 --- a/Maple2.Server.Game/PacketHandlers/JobHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/JobHandler.cs @@ -93,7 +93,7 @@ private void HandleAdvance(GameSession session, IByteReader packet) { session.Player.Buffs.Clear(); session.Player.Buffs.Initialize(); - session.Player.Buffs.LoadFieldBuffs(); + session.Player.Buffs.LoadFieldBuffs(session.ServerTableMetadata.ConstantsTable.shadowWorldBuffHpUp, session.ServerTableMetadata.ConstantsTable.shadowWorldBuffMoveProtect); session.Stats.Refresh(); session.Field.Broadcast(JobPacket.Advance(session.Player, session.Config.Skill.SkillInfo)); session.ConditionUpdate(ConditionType.job, codeLong: (int) session.NpcScript.JobCondition.ChangeToJobCode); diff --git a/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs b/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs index 763f3f9ac..2bb305f3e 100644 --- a/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs @@ -151,10 +151,10 @@ private void HandleListItem(GameSession session, IByteReader packet) { Look = item.Template, Blueprint = item.Blueprint ?? new ItemBlueprint(), Status = UgcMarketListingStatus.Active, - PromotionEndTime = promote ? DateTime.Now.AddHours(Constant.UGCShopAdHour).ToEpochSeconds() : 0, - ListingEndTime = DateTime.Now.AddDays(Constant.UGCShopSaleDay).ToEpochSeconds(), + PromotionEndTime = promote ? DateTime.Now.AddHours(session.ServerTableMetadata.ConstantsTable.UGCShopAdHour).ToEpochSeconds() : 0, + ListingEndTime = DateTime.Now.AddDays(session.ServerTableMetadata.ConstantsTable.UGCShopSaleDay).ToEpochSeconds(), CreationTime = DateTime.Now.ToEpochSeconds(), - Price = Math.Clamp(price, Constant.UGCShopSellMinPrice, Constant.UGCShopSellMaxPrice), + Price = Math.Clamp(price, session.ServerTableMetadata.ConstantsTable.UGCShopSellMinPrice, session.ServerTableMetadata.ConstantsTable.UGCShopSellMaxPrice), TabId = tabId, }; @@ -198,8 +198,8 @@ private void HandleRelistItem(GameSession session, IByteReader packet) { } item.Price = price; - item.PromotionEndTime = promote ? DateTime.Now.AddHours(Constant.UGCShopAdHour).ToEpochSeconds() : 0; - item.ListingEndTime = DateTime.Now.AddDays(Constant.UGCShopSaleDay).ToEpochSeconds(); + item.PromotionEndTime = promote ? DateTime.Now.AddHours(session.ServerTableMetadata.ConstantsTable.UGCShopAdHour).ToEpochSeconds() : 0; + item.ListingEndTime = DateTime.Now.AddDays(session.ServerTableMetadata.ConstantsTable.UGCShopSaleDay).ToEpochSeconds(); item.Status = UgcMarketListingStatus.Active; item.Description = description; item.Tags = tags; diff --git a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs index 7fe758d4a..cf3ccffd2 100644 --- a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs @@ -59,7 +59,7 @@ private static void HandleCreate(GameSession session, IByteReader packet) { long amount = packet.ReadLong(); long price = packet.ReadLong(); - if (amount != Constant.MesoMarketBasePrice) { + if (amount != session.ServerTableMetadata.ConstantsTable.MesoMarketBasePrice) { session.Send(MesoMarketPacket.Error(s_mesoMarket_error_invalidSaleMoney)); return; } @@ -96,7 +96,7 @@ private static void HandleCreate(GameSession session, IByteReader packet) { } session.Player.Value.Account.MesoMarketListed++; - session.Currency.Meso -= Constant.MesoMarketBasePrice; + session.Currency.Meso -= session.ServerTableMetadata.ConstantsTable.MesoMarketBasePrice; session.Send(MesoMarketPacket.Create(listing)); session.Send(MesoMarketPacket.Quota(session.Player.Value.Account.MesoMarketListed, session.Player.Value.Account.MesoMarketPurchased)); } diff --git a/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs b/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs index f1ffb3df4..cf21366ae 100644 --- a/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs @@ -237,7 +237,7 @@ private void HandleEnchant(GameSession session, IByteReader packet) { case ScriptEventType.EnchantSelect: case ScriptEventType.PeachySelect: if (!session.ScriptMetadata.TryGet(npcId, out ScriptMetadata? script) || - !script.States.TryGetValue(Constant.EnchantMasterScriptID, out ScriptState? state)) { + !script.States.TryGetValue(session.ServerTableMetadata.ConstantsTable.EnchantMasterScriptID, out ScriptState? state)) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/PartyHandler.cs b/Maple2.Server.Game/PacketHandlers/PartyHandler.cs index 0f8688b2e..2803d3a5c 100644 --- a/Maple2.Server.Game/PacketHandlers/PartyHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/PartyHandler.cs @@ -285,7 +285,8 @@ private void HandleVoteKick(GameSession session, IByteReader packet) { return; } - if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(Constant.PartyVoteReadyDurationSeconds) > DateTime.Now && session.Party.Party.Vote != null) { + if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(session.ServerTableMetadata.ConstantsTable.PartyVoteReadyDurationSeconds) + > DateTime.Now && session.Party.Party.Vote != null) { session.Send(PartyPacket.Error(PartyError.s_party_err_already_vote)); return; } @@ -315,7 +316,8 @@ private void HandleReadyCheck(GameSession session) { return; } - if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(Constant.PartyVoteReadyDurationSeconds) > DateTime.Now && session.Party.Party.Vote != null) { + if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(session.ServerTableMetadata.ConstantsTable.PartyVoteReadyDurationSeconds) > + DateTime.Now && session.Party.Party.Vote != null) { session.Send(PartyPacket.Error(PartyError.s_party_err_already_vote)); return; } diff --git a/Maple2.Server.Game/PacketHandlers/QuestHandler.cs b/Maple2.Server.Game/PacketHandlers/QuestHandler.cs index 4a94bcd3f..9da442bb9 100644 --- a/Maple2.Server.Game/PacketHandlers/QuestHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/QuestHandler.cs @@ -270,8 +270,8 @@ private static void HandleSkyFortressTeleport(GameSession session) { return; } - session.Send(session.PrepareField(Constant.FameContentsSkyFortressGotoMapID, - Constant.FameContentsSkyFortressGotoPortalID) + session.Send(session.PrepareField(session.ServerTableMetadata.ConstantsTable.FameContentsSkyFortressGotoMapID, + session.ServerTableMetadata.ConstantsTable.FameContentsSkyFortressGotoPortalID) ? FieldEnterPacket.Request(session.Player) : FieldEnterPacket.Error(MigrationError.s_move_err_default)); } diff --git a/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs b/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs index b9a9df184..4572c9405 100644 --- a/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs @@ -47,11 +47,11 @@ private void HandleArena(GameSession session, IByteReader packet) { return; } - if (!session.NpcMetadata.TryGet(Constant.SystemShopNPCIDHonorToken, out NpcMetadata? npc)) { + if (!session.NpcMetadata.TryGet(session.ServerTableMetadata.ConstantsTable.SystemShopNPCIDHonorToken, out NpcMetadata? npc)) { return; } - session.Shop.Load(npc.Basic.ShopId, Constant.SystemShopNPCIDHonorToken); + session.Shop.Load(npc.Basic.ShopId, session.ServerTableMetadata.ConstantsTable.SystemShopNPCIDHonorToken); session.Send(SystemShopPacket.Arena()); } @@ -61,7 +61,7 @@ private void HandleFishing(GameSession session, IByteReader packet) { session.Shop.ClearActiveShop(); return; } - if (!session.NpcMetadata.TryGet(Constant.SystemShopNPCIDFishing, out NpcMetadata? npc)) { + if (!session.NpcMetadata.TryGet(session.ServerTableMetadata.ConstantsTable.SystemShopNPCIDFishing, out NpcMetadata? npc)) { return; } @@ -76,7 +76,7 @@ private void HandleMentee(GameSession session, IByteReader packet) { return; } - if (!session.NpcMetadata.TryGet(Constant.SystemShopNPCIDMentee, out NpcMetadata? npc)) { + if (!session.NpcMetadata.TryGet(session.ServerTableMetadata.ConstantsTable.SystemShopNPCIDMentee, out NpcMetadata? npc)) { return; } @@ -91,7 +91,7 @@ private void HandleMentor(GameSession session, IByteReader packet) { return; } - if (!session.NpcMetadata.TryGet(Constant.SystemShopNPCIDMentor, out NpcMetadata? npc)) { + if (!session.NpcMetadata.TryGet(session.ServerTableMetadata.ConstantsTable.SystemShopNPCIDMentor, out NpcMetadata? npc)) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs b/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs index 40ecdfe2a..68a17c7d5 100644 --- a/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs @@ -180,7 +180,7 @@ private void HandleWorld(GameSession session, string message, ICollection } session.Send(NoticePacket.Notice(NoticePacket.Flags.Alert | NoticePacket.Flags.Message, StringCode.s_worldchat_use_coupon)); } else { - int meretCost = Constant.MeretConsumeWorldChat; + int meretCost = session.ServerTableMetadata.ConstantsTable.MeratConsumeWorldChat; if (session.FindEvent(GameEventType.SaleChat).FirstOrDefault()?.Metadata.Data is SaleChat gameEvent) { meretCost -= (int) (meretCost * Convert.ToSingle(gameEvent.WorldChatDiscount) / 10000); } @@ -215,7 +215,7 @@ private void HandleChannel(GameSession session, string message, ICollection item.Enchant?.Enchants) { + if (session.ServerTableMetadata.ConstantsTable.enchantSuccessBroadcastingLevel > item.Enchant?.Enchants) { return; } diff --git a/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs b/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs index 70bc77d38..2a863461d 100644 --- a/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs +++ b/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs @@ -45,6 +45,7 @@ private enum Command : byte { public required BanWordStorage BanWordStorage { private get; init; } public required ItemMetadataStorage ItemMetadata { private get; init; } public required TableMetadataStorage TableMetadata { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } // ReSharper restore All #endregion @@ -58,13 +59,15 @@ public override void Handle(LoginSession session, IByteReader packet) { HandleCreate(session, packet); break; case Command.Delete: - HandleDelete(session, packet); + HandleDelete(session, packet, ServerTableMetadata.ConstantsTable.CharacterDestroyDivisionLevel, + ServerTableMetadata.ConstantsTable.CharacterDestroyWaitSecond); break; case Command.CancelDelete: HandleCancelDelete(session, packet); break; case Command.ConfirmDelete: - HandleDelete(session, packet); + HandleDelete(session, packet, ServerTableMetadata.ConstantsTable.CharacterDestroyDivisionLevel, + ServerTableMetadata.ConstantsTable.CharacterDestroyWaitSecond); break; default: throw new ArgumentException($"Invalid CHARACTER_MANAGEMENT type {command}"); @@ -198,7 +201,7 @@ private void HandleCreate(LoginSession session, IByteReader packet) { session.CreateCharacter(character, outfits); } - private void HandleDelete(LoginSession session, IByteReader packet) { + private void HandleDelete(LoginSession session, IByteReader packet, int characterDestroyDivisionLevel, int characterDestroyWaitSecond) { long characterId = packet.ReadLong(); using GameStorage.Request db = GameStorage.Context(); @@ -218,8 +221,8 @@ private void HandleDelete(LoginSession session, IByteReader packet) { return; } - if (character.Level >= Constant.CharacterDestroyDivisionLevel) { - character.DeleteTime = DateTimeOffset.UtcNow.AddSeconds(Constant.CharacterDestroyWaitSecond).ToUnixTimeSeconds(); + if (character.Level >= characterDestroyDivisionLevel) { + character.DeleteTime = DateTimeOffset.UtcNow.AddSeconds(characterDestroyWaitSecond).ToUnixTimeSeconds(); if (db.UpdateDelete(session.AccountId, characterId, character.DeleteTime)) { session.Send(CharacterListPacket.BeginDelete(characterId, character.DeleteTime)); } else { diff --git a/Maple2.Server.World/WorldServer.cs b/Maple2.Server.World/WorldServer.cs index a8046de75..f83e77872 100644 --- a/Maple2.Server.World/WorldServer.cs +++ b/Maple2.Server.World/WorldServer.cs @@ -332,7 +332,7 @@ public void FieldPlotExpiryCheck() { SetPlotAsPending(db, plot); forfeit = true; // mark as open when 3 days has passed since the expiry time - } else if (plot.OwnerId == 0 && plot.ExpiryTime + Constant.UgcHomeSaleWaitingTime.TotalSeconds < DateTimeOffset.UtcNow.ToUnixTimeSeconds()) { + } else if (plot.OwnerId == 0 && plot.ExpiryTime + serverTableMetadata.ConstantsTable.UgcHomeSaleWaitingTime.TotalSeconds < DateTimeOffset.UtcNow.ToUnixTimeSeconds()) { logger.Information("Marking plot {PlotId} as open (no owner)", plot.Id); db.SetPlotOpen(plot.Id); // Mark as open } else { @@ -359,7 +359,7 @@ public void FieldPlotExpiryCheck() { } // Schedule next check for the next soonest expiry - PlotInfo? nextPlot = db.GetSoonestPlotFromExpire(); + PlotInfo? nextPlot = db.GetSoonestPlotFromExpire(serverTableMetadata.ConstantsTable.UgcHomeSaleWaitingTime); TimeSpan delay; if (nextPlot is not null) { DateTimeOffset nextExpiry = DateTimeOffset.FromUnixTimeSeconds(nextPlot.ExpiryTime); From 3f5414d1c78844bff119dee625cd232f73093275 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Thu, 26 Feb 2026 16:49:06 -0600 Subject: [PATCH 05/26] Continue switching hard coded constants to server constants pared during file ingest #3 WIP --- Maple2.File.Ingest/Mapper/NpcMapper.cs | 15 +++---- Maple2.Model/Game/Npc/Npc.cs | 12 +++++- Maple2.Model/Metadata/NpcMetadata.cs | 43 ++++++++++++++++--- .../Field/FieldManager/FieldManager.State.cs | 8 +++- .../Model/Field/Actor/FieldNpc.cs | 15 ++++--- .../Model/Field/Actor/FieldPet.cs | 4 +- 6 files changed, 69 insertions(+), 28 deletions(-) diff --git a/Maple2.File.Ingest/Mapper/NpcMapper.cs b/Maple2.File.Ingest/Mapper/NpcMapper.cs index f0871acd6..81e76e8f8 100644 --- a/Maple2.File.Ingest/Mapper/NpcMapper.cs +++ b/Maple2.File.Ingest/Mapper/NpcMapper.cs @@ -31,14 +31,13 @@ protected override IEnumerable Map() { AniSpeed: data.model.anispeed ), Distance: new NpcMetadataDistance( - Avoid: data.distance.avoid, - Sight: data.distance.sight, - SightHeightUp: data.distance.sightHeightUP, - SightHeightDown: data.distance.sightHeightDown - // TODO: Need to move to runtime due to server table constants being used as default value - //LastSightRadius: data.distance.customLastSightRadius == 0 ? Constant.NpcLastSightRadius : data.distance.customLastSightRadius, - //LastSightHeightUp: data.distance.customLastSightHeightUp == 0 ? Constant.NpcLastSightHeightUp : data.distance.customLastSightHeightUp, - //LastSightHeightDown: data.distance.customLastSightHeightDown == 0 ? Constant.NpcLastSightHeightDown : data.distance.customLastSightHeightDown + data.distance.avoid, + data.distance.sight, + data.distance.sightHeightUP, + data.distance.sightHeightDown, + data.distance.customLastSightRadius, + data.distance.customLastSightHeightUp, + data.distance.customLastSightHeightDown ), Skill: new NpcMetadataSkill( Entries: data.skill.ids.Select((skillId, i) => diff --git a/Maple2.Model/Game/Npc/Npc.cs b/Maple2.Model/Game/Npc/Npc.cs index d135d541b..a2c341b3e 100644 --- a/Maple2.Model/Game/Npc/Npc.cs +++ b/Maple2.Model/Game/Npc/Npc.cs @@ -10,8 +10,16 @@ public class Npc { public bool IsBoss => Metadata.Basic.Friendly == 0 && Metadata.Basic.Class >= 3; - public Npc(NpcMetadata metadata, AnimationMetadata? animation) { - Metadata = metadata; + public Npc(NpcMetadata metadata, AnimationMetadata? animation, float constLastSightRadius, float constLastSightHeightUp, float constLastSightHeightDown) { + if (metadata.Distance.LastSightRadius == 0) { + Metadata = new NpcMetadata(metadata, constLastSightRadius); + } else if (metadata.Distance.LastSightRadius == 0 && metadata.Distance.LastSightHeightUp == 0) { + Metadata = new NpcMetadata(metadata, constLastSightRadius, constLastSightHeightUp); + } else if (metadata.Distance.LastSightRadius == 0 && metadata.Distance.LastSightHeightUp == 0 && metadata.Distance.LastSightHeightDown == 0) { + Metadata = new NpcMetadata(metadata, constLastSightRadius, constLastSightHeightUp, constLastSightHeightDown); + } else { + Metadata = metadata; + } Animations = animation?.Sequences ?? new Dictionary(); } } diff --git a/Maple2.Model/Metadata/NpcMetadata.cs b/Maple2.Model/Metadata/NpcMetadata.cs index 86ecf2af5..25f7579f7 100644 --- a/Maple2.Model/Metadata/NpcMetadata.cs +++ b/Maple2.Model/Metadata/NpcMetadata.cs @@ -1,4 +1,5 @@ -using System.Numerics; +using System.ComponentModel.Design; +using System.Numerics; using Maple2.Model.Enum; namespace Maple2.Model.Metadata; @@ -16,7 +17,28 @@ public record NpcMetadata( NpcMetadataDropInfo DropInfo, NpcMetadataAction Action, NpcMetadataDead Dead, - NpcMetadataLookAtTarget LookAtTarget) : ISearchResult; + NpcMetadataLookAtTarget LookAtTarget) : ISearchResult { + public NpcMetadata(NpcMetadata other, float lastSightRadius) : this(other.Id, + other.Name, other.AiPath, other.Model, other.Stat, other.Basic, other.Distance, other.Skill, other.Property, other.DropInfo, + other.Action, other.Dead, other.LookAtTarget) { + Distance = new NpcMetadataDistance(Distance.Avoid, Distance.Sight, Distance.SightHeightUp, + Distance.SightHeightDown, lastSightRadius, Distance.LastSightHeightUp, Distance.LastSightHeightDown); + } + + public NpcMetadata(NpcMetadata other, float lastSightRadius, float lastSightHeightUp) : this(other.Id, + other.Name, other.AiPath, other.Model, other.Stat, other.Basic, other.Distance, other.Skill, other.Property, other.DropInfo, + other.Action, other.Dead, other.LookAtTarget) { + Distance = new NpcMetadataDistance(Distance.Avoid, Distance.Sight, Distance.SightHeightUp, + Distance.SightHeightDown, lastSightRadius, lastSightHeightUp, Distance.LastSightHeightDown); + } + + public NpcMetadata(NpcMetadata other, float lastSightRadius, float lastSightHeightUp, float lastSightHeightDown) : this(other.Id, + other.Name, other.AiPath, other.Model, other.Stat, other.Basic, other.Distance, other.Skill, other.Property, other.DropInfo, + other.Action, other.Dead, other.LookAtTarget) { + Distance = new NpcMetadataDistance(Distance.Avoid, Distance.Sight, Distance.SightHeightUp, + Distance.SightHeightDown, lastSightRadius, lastSightHeightUp, lastSightHeightDown); + } +} public record NpcMetadataModel( string Name, @@ -34,11 +56,18 @@ public record NpcMetadataDistance( float Avoid, float Sight, float SightHeightUp, - float SightHeightDown - // TODO: Need to move to runtime due to server table constants being used as default value - /* float LastSightRadius, - float LastSightHeightUp, - float LastSightHeightDown*/); + float SightHeightDown) { + public NpcMetadataDistance(float avoid, float sight, float sightHeightUp, float sightHeightDown, float lastSightRadius, + float lastSightHeightUp, float lastSightHeightDown) : this(avoid, sight, sightHeightUp, sightHeightDown) { + LastSightRadius = lastSightRadius; + LastSightHeightUp = lastSightHeightUp; + LastSightHeightDown = lastSightHeightDown; + } + + public float LastSightRadius { get; private set; } + public float LastSightHeightUp { get; private set; } + public float LastSightHeightDown { get; private set; } +} public record NpcMetadataSkill( NpcMetadataSkill.Entry[] Entries, diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs index 59d0d66e9..655c53dd6 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs @@ -133,7 +133,9 @@ public FieldPlayer SpawnPlayer(GameSession session, Player player, int portalId AnimationMetadata? animation = NpcMetadata.GetAnimation(npc.Model.Name); string aiPath = disableAi ? string.Empty : npc.AiPath; - var fieldNpc = new FieldNpc(this, NextLocalId(), agent, new Npc(npc, animation), aiPath, patrolDataUUID: spawnPointNpc?.PatrolData, spawnAnimation: spawnAnimation) { + var fieldNpc = new FieldNpc(this, NextLocalId(), agent, new Npc(npc, animation, ServerTableMetadata.ConstantsTable.NpcLastingSightRadius, + ServerTableMetadata.ConstantsTable.NpcLastingSightHeightUp, ServerTableMetadata.ConstantsTable.NpcLastingSightHeightDown), aiPath, + patrolDataUUID: spawnPointNpc?.PatrolData, spawnAnimation: spawnAnimation) { Owner = owner, Position = spawnPosition, Rotation = rotation, @@ -171,7 +173,9 @@ public FieldPlayer SpawnPlayer(GameSession session, Player player, int portalId int objectId = player != null ? NextGlobalId() : NextLocalId(); AnimationMetadata? animation = NpcMetadata.GetAnimation(npc.Model.Name); - var fieldPet = new FieldPet(this, objectId, agent, new Npc(npc, animation), pet, petMetadata, Constant.PetFieldAiPath, player) { + var fieldPet = new FieldPet(this, objectId, agent, new Npc(npc, animation, ServerTableMetadata.ConstantsTable.NpcLastingSightRadius, + ServerTableMetadata.ConstantsTable.NpcLastingSightHeightUp,ServerTableMetadata.ConstantsTable.NpcLastingSightHeightDown), + pet, petMetadata, Constant.PetFieldAiPath, player) { Owner = owner, Position = position, Rotation = rotation, diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldNpc.cs b/Maple2.Server.Game/Model/Field/Actor/FieldNpc.cs index bb94336fe..cacc29a6a 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldNpc.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldNpc.cs @@ -1,20 +1,21 @@ -using System.Diagnostics.CodeAnalysis; -using System.Numerics; +using DotRecast.Detour.Crowd; +using Maple2.Database.Storage; using Maple2.Model.Enum; using Maple2.Model.Game; using Maple2.Model.Metadata; +using Maple2.Server.Core.Packets; using Maple2.Server.Game.Manager.Field; +using Maple2.Server.Game.Model.ActorStateComponent; +using Maple2.Server.Game.Model.Enum; using Maple2.Server.Game.Model.Skill; using Maple2.Server.Game.Model.State; using Maple2.Server.Game.Packets; +using Maple2.Server.Game.Session; using Maple2.Tools; using Maple2.Tools.Collision; -using Maple2.Server.Game.Session; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; using static Maple2.Server.Game.Model.ActorStateComponent.TaskState; -using Maple2.Server.Game.Model.Enum; -using Maple2.Server.Core.Packets; -using DotRecast.Detour.Crowd; -using Maple2.Server.Game.Model.ActorStateComponent; using MovementState = Maple2.Server.Game.Model.ActorStateComponent.MovementState; namespace Maple2.Server.Game.Model; diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs b/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs index 94c2005c5..accb7b90e 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs @@ -64,7 +64,7 @@ public override void ApplyDamage(IActor caster, DamageRecord damage, SkillMetada } var targetRecord = new DamageRecordTarget(this); - int damageAmount = TamingPoint - Math.Min(TamingPoint + attack.Pet.TamingPoint, Constant.TamingPetMaxPoint); + int damageAmount = TamingPoint - Math.Min(TamingPoint + attack.Pet.TamingPoint, Field.ServerTableMetadata.ConstantsTable.TamingPetMaxPoint); TamingPoint -= damageAmount; targetRecord.AddDamage(damageAmount == 0 ? DamageType.Miss : DamageType.Normal, damageAmount); @@ -73,7 +73,7 @@ public override void ApplyDamage(IActor caster, DamageRecord damage, SkillMetada IsDead = true; OnDeath(); DropItem(caster); - } else if (TamingPoint >= Constant.TamingPetMaxPoint) { // trap has chance to fail + } else if (TamingPoint >= Field.ServerTableMetadata.ConstantsTable.TamingPetMaxPoint) { // trap has chance to fail IsDead = true; OnDeath(); DropItem(caster); From f633b68aeb9d662b3930e0c2044eafe28dd8e459 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Fri, 27 Feb 2026 16:59:02 -0600 Subject: [PATCH 06/26] Fix last hard coded constant value in PartyManager. Add in input cleaning and non-IConvertible data types handling during constant parsing. --- .../Mapper/ServerTableMapper.cs | 73 ++++++++++++++- .../Metadata/ServerTable/ConstantsTable.cs | 88 ++++++++++--------- Maple2.Server.World/Containers/PartyLookup.cs | 9 +- .../Containers/PartyManager.cs | 10 ++- Maple2.Server.World/Program.cs | 3 + 5 files changed, 133 insertions(+), 50 deletions(-) diff --git a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs index a90687aa7..2818ebe62 100644 --- a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs +++ b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs @@ -3,6 +3,7 @@ using Maple2.File.IO; using Maple2.File.Parser; using Maple2.File.Parser.Enum; +using Maple2.File.Parser.Flat.Convert; using Maple2.File.Parser.Xml.Table.Server; using Maple2.Model; using Maple2.Model.Common; @@ -12,6 +13,7 @@ using Maple2.Model.Game.Shop; using Maple2.Model.Metadata; using System.Globalization; +using System.Numerics; using System.Reflection; using System.Xml; using DayOfWeek = System.DayOfWeek; @@ -2118,11 +2120,78 @@ private ConstantsTable ParseConstants() { PropertyInfo[] constantsProperties = constants.GetType().GetProperties(); foreach (PropertyInfo constantsProperty in constantsProperties) { foreach ((string key, Parser.Xml.Table.Constants.Key constant) in parser.ParseConstants()) { - if (!key.Trim().Equals(constantsProperty.Name.Trim())) continue; - constantsProperty.SetValue(constants, Convert.ChangeType(constant.value, constantsProperty.PropertyType)); + string constantPropertyName = constantsProperty.Name.Trim(); + if (!key.Trim().Equals(constantPropertyName)) continue; + Type constantsPropertyType = constantsProperty.PropertyType; + string cleanConstantValue = CleanConstantsInput(constant.value.Trim(), constantPropertyName, constantsPropertyType); + SetValue(constantsProperty, constants, cleanConstantValue); break; } } return constants; } + + private string CleanConstantsInput(string input, string propName, Type type) { + // check if string contains the ending 'f' for float designation, strip it if it does. + if (type == typeof(float) && input.Contains('f')) { + input = input.TrimEnd('f', 'F'); + } + // 1 does not automatically equate to true during bool conversion + if (type == typeof(bool) && input == "1") { + input = "true"; + } + // 0 does not automatically equate to false during bool conversion + if (type == typeof(bool) && input == "0") { + input = "false"; + } + // Convert into a TimeSpan friendly input string instead of an int value + if (type == typeof(TimeSpan) && propName == "UgcHomeSaleWaitingTime") { + input = TimeSpan.FromSeconds(int.Parse(input)).ToString(); // TODO: may not be correct conversion to TimeSpan + } + // Remove prefix 0 on integers since they do not convert properly + if (type == typeof(int) && input[0] == '0' && input.Length > 1) { + input = input.Remove(0, 1); + } + return input; + } + + private void SetValue(PropertyInfo prop, object? obj, object? value) { + if (obj == null && value == null || value == null) return; + HandleNonIConvertibleTypes(prop, ref value); + bool isConvertible = typeof(IConvertible).IsAssignableFrom(prop.PropertyType); + prop.SetValue(obj, isConvertible ? Convert.ChangeType(value, prop.PropertyType, CultureInfo.InvariantCulture) : value); + } + + private object? HandleNonIConvertibleTypes(PropertyInfo prop, ref object? value) { + if (value == null) return value; + // Handle TimeSpan type + if (prop.PropertyType == typeof(TimeSpan)) { + // Special case - dashes (-) are used instead of colons (:) + if (prop.Name == "DailyTrophyResetDate") { + value = ((string)value).Replace('-', ':'); + } + value = TimeSpan.Parse((string)value, CultureInfo.InvariantCulture); + } + // Handle array types (int[], short[], etc.) + if (prop.PropertyType.IsArray) { + var elementType = prop.PropertyType.GetElementType(); + if (elementType == null) return value; + string[] segments = ((string)value).Split(','); + Array destinationArray = Array.CreateInstance(elementType, segments.Length); + for (int i = 0; i < segments.Length; i++) { + object convertedValue = Convert.ChangeType(segments[i].Trim(), elementType); + destinationArray.SetValue(convertedValue, i); + } + value = destinationArray; + } + // Handle Vector3 type + if (prop.PropertyType == typeof(Vector3)) { + string[] parts = ((string) value).Split(','); + if (parts.Length != 3) return value; + value = new Vector3(float.Parse(parts[0], CultureInfo.InvariantCulture), + float.Parse(parts[1], CultureInfo.InvariantCulture), + float.Parse(parts[2], CultureInfo.InvariantCulture)); + } + return value; + } } diff --git a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs index edb544f78..7eb6b6870 100644 --- a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs +++ b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs @@ -1,4 +1,6 @@ -namespace Maple2.Model.Metadata; +using System.Numerics; + +namespace Maple2.Model.Metadata; public record ConstantsTable( float NPCColorScale = 0f, @@ -116,8 +118,8 @@ public record ConstantsTable( string UserRevivalInvincibleIconPath = "", int GetExpMinVelocity = 0, int GetExpVelocityPer1Length = 0, - string GetExpControlValue0 = "", - string GetExpControlValue1 = "", + float[] GetExpControlValue0 = null!, + float[] GetExpControlValue1 = null!, string GetExpTargetPCDummyName = "", float GetExpTimeAcceleration = 0f, float GetExpCollisionRadius = 0f, @@ -158,18 +160,18 @@ public record ConstantsTable( float BossHpBarDuration = 0f, float FindHoldTargetRange = 0f, int FindGrabNodeRange = 0, - string UgcShopCharCameraLookat = "", - string UgcShopCharCameraPos = "", - int UgcShopCharCameraMinDistance = 0, - int UgcShopCharCameraZoomVelocity = 0, - string UgcShopCubeCameraLookat = "", - string UgcShopCubeCameraPos = "", - int UgcShopCubeCameraMinDistance = 0, - int UgcShopCubeCameraZoomVelocity = 0, - string UgcShopRideeCameraLookat = "", - string UgcShopRideeCameraPos = "", - int UgcShopRideeCameraMinDistance = 0, - int UgcShopRideeCameraZoomVelocity = 0, + Vector3 UgcshopCharCameraLookat = default, + Vector3 UgcshopCharCameraPos = default, + int UgcshopCharCameraMinDistance = 0, + int UgcshopCharCameraZoomVelocity = 0, + Vector3 UgcshopCubeCameraLookat = default, + Vector3 UgcshopCubeCameraPos = default, + int UgcshopCubeCameraMinDistance = 0, + int UgcshopCubeCameraZoomVelocity = 0, + Vector3 UgcshopRideeCameraLookat = default, + Vector3 UgcshopRideeCameraPos = default, + int UgcshopRideeCameraMinDistance = 0, + int UgcshopRideeCameraZoomVelocity = 0, int FieldCachingCount = 0, float FieldCachingTime = 0f, int FieldCachingMaxCount = 0, @@ -213,8 +215,8 @@ public record ConstantsTable( int returnHomeSkill = 0, int returnHomeSkillMeret = 0, int TutorialIntroSkipTime = 0, - string AvatarDefaultItemMale = "", - string AvatarDefaultItemFemale = "", + int[] AvatarDefaultItemMale = null!, + int[] AvatarDefaultItemFemale = null!, int TalkCooldown = 0, int AddressPopupDuration = 0, int MaxFPS = 0, @@ -225,8 +227,8 @@ public record ConstantsTable( int UGCShopAdHour = 0, int UGCShopSellingRestrictAmount = 0, int MeretMarketHomeBannerShowTick = 0, - int BlackMarketSellMinPrice = 0, - int BlackMarketSellMaxPrice = 0, + long BlackMarketSellMinPrice = 0, + long BlackMarketSellMaxPrice = 0, int BlackMarketSellEndDay = 0, int ItemTransferBlackMarketGrade = 0, int UgcBannerCheckTime = 0, @@ -382,7 +384,7 @@ public record ConstantsTable( int guildPVPMatchingTime = 0, int guildPVPWinPoint = 0, int guildPVPLosePoint = 0, - string guildPVPAdditionalEffect = "", + int[] guildPVPAdditionalEffect = null!, int ModePvPRecoverySkill = 0, int ModePvPRecoverySP = 0, int ModePvPInvincibleTime = 0, @@ -394,10 +396,10 @@ public record ConstantsTable( int PvpGuildRewardItem = 0, int PvpGuildRewardWinnerCount = 0, int PvpGuildRewardLoserCount = 0, - string ModePVPRedArenaAdditionalEffect = "", + int[] ModePVPRedArenaAdditionalEffect = null!, int ModePvPScoreDead = -50, int ModePvPScoreKill = 100, - string ModePVPBloodMineAdditionalEffect = "", + int[] ModePVPBloodMineAdditionalEffect = null!, int pvpFFAShortComboTick = 0, int pvpFFALongComboTick = 0, int pvpFFASlayerCount = 0, @@ -416,7 +418,7 @@ public record ConstantsTable( int PvpFFAAdditionRewardRate = 0, int rankDuelPvpMatchingTime = 0, int rankDuelPvpMatchingMinGap = 0, - string ModePVPDuelRankArenaAdditionalEffect = "", + int[] ModePVPDuelRankArenaAdditionalEffect = null!, int MailExpiryDays = 0, int MailExpiryDaysPremium = 0, int MailExpiryDaysBlackMarket = 0, @@ -671,21 +673,21 @@ public record ConstantsTable( int PetTrapDropVisibleDelay = 0, int PetMaxLevel = 0, string VisitorBookURL = "", - short bagSlotTabGameCount = 0, - short bagSlotTabSkinCount = 0, - short bagSlotTabSummonCount = 0, - short bagSlotTabMaterialCount = 0, - short bagSlotTabMasteryCount = 0, - short bagSlotTabLifeCount = 0, - short bagSlotTabQuestCount = 0, - short bagSlotTabGemCount = 0, - short bagSlotTabPetCount = 0, - short bagSlotTabActiveSkillCount = 0, - short bagSlotTabCoinCount = 0, - short bagSlotTabBadgeCount = 0, - short bagSlotTabMiscCount = 0, - short bagSlotTabLapenShardCount = 0, - short bagSlotTabPieceCount = 0, + short[] bagSlotTabGameCount = null!, + short[] bagSlotTabSkinCount = null!, + short[] bagSlotTabSummonCount = null!, + short[] bagSlotTabMaterialCount = null!, + short[] bagSlotTabMasteryCount = null!, + short[] bagSlotTabLifeCount = null!, + short[] bagSlotTabQuestCount = null!, + short[] bagSlotTabGemCount = null!, + short[] bagSlotTabPetCount = null!, + short[] bagSlotTabActiveSkillCount = null!, + short[] bagSlotTabCoinCount = null!, + short[] bagSlotTabBadgeCount = null!, + short[] bagSlotTabMiscCount = null!, + short[] bagSlotTabLapenShardCount = null!, + short[] bagSlotTabPieceCount = null!, int MasteryObjectInteractionDistance = 0, float GatheringObjectMarkOffsetX = 0f, float GatheringObjectMarkOffsetY = 0f, @@ -790,7 +792,7 @@ public record ConstantsTable( int UgcNameLengthMax = 0, int UgcTagLengthMax = 0, int ChangeJobLevel = 0, - int LapenShardOpenQuestID = 0, + int[] LapenShardOpenQuestID = null!, int MaidNameLengthMin = 0, int MaidNameLengthMax = 0, int MaidDescLengthMin = 0, @@ -803,13 +805,13 @@ public record ConstantsTable( int MouseInteractLimitDistance = 0, int AutoInstallEquipmentMinLevel = 0, int AutoInstallEquipmentMaxLevel = 0, - string PartySearchRegisterComboValues = "", + int[] PartySearchRegisterComboValues = null!, int FieldWarInstanceEnterableDurationSeconds = 0, int FieldWarRequirePlayerCount = 0, int FieldWarRequireAchieveID = 0, int FieldWarRequireLevel = 0, int StatScaleMarkingAdditionalEffect = 0, - string DungeonRewardFailEmotions = "", + int[] DungeonRewardFailEmotions = null!, int SummonPetSkillID = 0, int UGCMapSetItemEffectCountLimit = 0, int AdventureLevelMissionResetWeekday = 0, @@ -850,8 +852,8 @@ public record ConstantsTable( int PvpOnePunchRewardItem = 0, int PvpOnePunchScoreNpcKill = 0, int SpecialHairShopID = 0, - string GemStoneProbList = "", - string SkinGemStoneProbList = "", + int[] GemStoneProbList = null!, + int[] SkinGemStoneProbList = null!, string PersonalInfoAgreementURL = "", float BothHandLowDamageRatio = 0f, float BothHandWeaponDamagePenaltyDiv = 0f, diff --git a/Maple2.Server.World/Containers/PartyLookup.cs b/Maple2.Server.World/Containers/PartyLookup.cs index 29ece3e4c..a1f774b46 100644 --- a/Maple2.Server.World/Containers/PartyLookup.cs +++ b/Maple2.Server.World/Containers/PartyLookup.cs @@ -1,5 +1,6 @@ using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; +using Maple2.Database.Storage; using Maple2.Model.Error; using Maple2.Model.Game; using Maple2.Model.Game.Party; @@ -10,6 +11,8 @@ public class PartyLookup : IDisposable { private readonly ChannelClientLookup channelClients; private readonly PlayerInfoLookup playerLookup; private readonly PartySearchLookup partySearchLookup; + private ServerTableMetadataStorage serverTableMetadataStorage; + private readonly ConcurrentDictionary parties; private int nextPartyId = 1; @@ -22,6 +25,10 @@ public PartyLookup(ChannelClientLookup channelClients, PlayerInfoLookup playerLo parties = new ConcurrentDictionary(); } + public void InjectDependencies(ServerTableMetadataStorage serverTableMetadataStorage) { + this.serverTableMetadataStorage = serverTableMetadataStorage; + } + public void Dispose() { foreach (PartyManager manager in parties.Values) { manager.Dispose(); @@ -56,7 +63,7 @@ public PartyError Create(long leaderId, out int partyId) { } var party = new Party(partyId, leaderInfo.AccountId, leaderInfo.CharacterId, leaderInfo.Name); - var manager = new PartyManager(party) { + var manager = new PartyManager(party, serverTableMetadataStorage.ConstantsTable.PartyVoteReadyDurationSeconds) { ChannelClients = channelClients, PartyLookup = this, }; diff --git a/Maple2.Server.World/Containers/PartyManager.cs b/Maple2.Server.World/Containers/PartyManager.cs index 837254313..a38467520 100644 --- a/Maple2.Server.World/Containers/PartyManager.cs +++ b/Maple2.Server.World/Containers/PartyManager.cs @@ -1,10 +1,10 @@ using System.Collections.Concurrent; using Grpc.Core; +using Maple2.Database.Storage; using Maple2.Model.Enum; using Maple2.Model.Error; using Maple2.Model.Game; using Maple2.Model.Game.Party; -using Maple2.Model.Metadata; using Maple2.Server.Channel.Service; using ChannelClient = Maple2.Server.Channel.Service.Channel.ChannelClient; @@ -15,10 +15,12 @@ public class PartyManager : IDisposable { public required PartyLookup PartyLookup { get; init; } public readonly Party Party; private readonly ConcurrentDictionary pendingInvites; + private readonly int partyVoteReadyDurationSeconds; - public PartyManager(Party party) { + public PartyManager(Party party, int partyVoteReadyDurationSeconds) { Party = party; pendingInvites = new ConcurrentDictionary(); + this.partyVoteReadyDurationSeconds = partyVoteReadyDurationSeconds; } public void Dispose() { @@ -282,7 +284,7 @@ public PartyError StartReadyCheck(long requestorId) { }); Task.Factory.StartNew(() => { - Thread.Sleep(TimeSpan.FromSeconds(Constant.PartyVoteReadyDurationSeconds)); + Thread.Sleep(TimeSpan.FromSeconds(partyVoteReadyDurationSeconds)); if (Party.Vote == null) { return; } @@ -394,7 +396,7 @@ public PartyError VoteKick(long requestorId, long targetId) { Task.Factory.StartNew(() => { // TODO: The duration is wrong. - Thread.Sleep(TimeSpan.FromSeconds(Constant.PartyVoteReadyDurationSeconds)); + Thread.Sleep(TimeSpan.FromSeconds(partyVoteReadyDurationSeconds)); if (Party.Vote == null) { return; } diff --git a/Maple2.Server.World/Program.cs b/Maple2.Server.World/Program.cs index 6d34eafcd..64a59b226 100644 --- a/Maple2.Server.World/Program.cs +++ b/Maple2.Server.World/Program.cs @@ -84,7 +84,10 @@ .OnActivated(e => { var channelLookup = e.Context.Resolve(); var playerInfoLookup = e.Context.Resolve(); + var partyLookup = e.Context.Resolve(); + var serverTableMetadataStorage = e.Context.Resolve(); channelLookup.InjectDependencies(e.Instance, playerInfoLookup); + partyLookup.InjectDependencies(serverTableMetadataStorage); }) .SingleInstance(); }); From 24c70fa7d70945c6154e4737f93694eea104cd76 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Fri, 27 Feb 2026 22:28:41 -0600 Subject: [PATCH 07/26] Remove hard coded constants and utilize server constants within Inventory Manager. --- Maple2.Model/Metadata/Constants.cs | 16 ----- .../Manager/Items/InventoryManager.cs | 62 +++++++++---------- 2 files changed, 31 insertions(+), 47 deletions(-) diff --git a/Maple2.Model/Metadata/Constants.cs b/Maple2.Model/Metadata/Constants.cs index 13f94dac4..c609ce3f1 100644 --- a/Maple2.Model/Metadata/Constants.cs +++ b/Maple2.Model/Metadata/Constants.cs @@ -131,22 +131,6 @@ public static class Constant { public const int PartyFinderListingsPageCount = 12; public const int ProposalItemId = 11600482; public const int bagSlotTabPetEquipCount = 48; - public const int BagSlotTabGameCountMax = 48; - public const int BagSlotTabSkinCountMax = 150; - public const int BagSlotTabSummonCountMax = 48; - public const int BagSlotTabMaterialCountMax = 48; - public const int BagSlotTabMasteryCountMax = 48; - public const int BagSlotTabLifeCountMax = 48; - public const int BagSlotTabQuestCountMax = 48; - public const int BagSlotTabGemCountMax = 48; - public const int BagSlotTabPetCountMax = 78; - public const int BagSlotTabPetEquipCountMax = 48; - public const int BagSlotTabActiveSkillCountMax = 48; - public const int BagSlotTabCoinCountMax = 48; - public const int BagSlotTabBadgeCountMax = 48; - public const int BagSlotTabMiscCountMax = 48; - public const int BagSlotTabLapenshardCountMax = 48; - public const int BagSlotTabPieceCountMax = 48; public const int MeretAirTaxiPrice = 15; public const int ClubMaxCount = 3; diff --git a/Maple2.Server.Game/Manager/Items/InventoryManager.cs b/Maple2.Server.Game/Manager/Items/InventoryManager.cs index 78fc94e3b..87d3c6a88 100644 --- a/Maple2.Server.Game/Manager/Items/InventoryManager.cs +++ b/Maple2.Server.Game/Manager/Items/InventoryManager.cs @@ -46,42 +46,42 @@ public InventoryManager(GameStorage.Request db, GameSession session) { private short BaseSize(InventoryType type) { return type switch { - InventoryType.Gear => session.ServerTableMetadata.ConstantsTable.bagSlotTabGameCount, - InventoryType.Outfit => session.ServerTableMetadata.ConstantsTable.bagSlotTabSkinCount, - InventoryType.Mount => session.ServerTableMetadata.ConstantsTable.bagSlotTabSummonCount, - InventoryType.Catalyst => session.ServerTableMetadata.ConstantsTable.bagSlotTabMaterialCount, - InventoryType.FishingMusic => session.ServerTableMetadata.ConstantsTable.bagSlotTabLifeCount, - InventoryType.Quest => session.ServerTableMetadata.ConstantsTable.bagSlotTabQuestCount, - InventoryType.Gemstone => session.ServerTableMetadata.ConstantsTable.bagSlotTabGemCount, - InventoryType.Misc => session.ServerTableMetadata.ConstantsTable.bagSlotTabMiscCount, - InventoryType.LifeSkill => session.ServerTableMetadata.ConstantsTable.bagSlotTabMasteryCount, - InventoryType.Pets => session.ServerTableMetadata.ConstantsTable.bagSlotTabPetCount, - InventoryType.Consumable => session.ServerTableMetadata.ConstantsTable.bagSlotTabActiveSkillCount, - InventoryType.Currency => session.ServerTableMetadata.ConstantsTable.bagSlotTabCoinCount, - InventoryType.Badge => session.ServerTableMetadata.ConstantsTable.bagSlotTabBadgeCount, - InventoryType.Lapenshard => session.ServerTableMetadata.ConstantsTable.bagSlotTabLapenShardCount, - InventoryType.Fragment => session.ServerTableMetadata.ConstantsTable.bagSlotTabPieceCount, + InventoryType.Gear => session.ServerTableMetadata.ConstantsTable.bagSlotTabGameCount[0], + InventoryType.Outfit => session.ServerTableMetadata.ConstantsTable.bagSlotTabSkinCount[0], + InventoryType.Mount => session.ServerTableMetadata.ConstantsTable.bagSlotTabSummonCount[0], + InventoryType.Catalyst => session.ServerTableMetadata.ConstantsTable.bagSlotTabMaterialCount[0], + InventoryType.FishingMusic => session.ServerTableMetadata.ConstantsTable.bagSlotTabLifeCount[0], + InventoryType.Quest => session.ServerTableMetadata.ConstantsTable.bagSlotTabQuestCount[0], + InventoryType.Gemstone => session.ServerTableMetadata.ConstantsTable.bagSlotTabGemCount[0], + InventoryType.Misc => session.ServerTableMetadata.ConstantsTable.bagSlotTabMiscCount[0], + InventoryType.LifeSkill => session.ServerTableMetadata.ConstantsTable.bagSlotTabMasteryCount[0], + InventoryType.Pets => session.ServerTableMetadata.ConstantsTable.bagSlotTabPetCount[0], + InventoryType.Consumable => session.ServerTableMetadata.ConstantsTable.bagSlotTabActiveSkillCount[0], + InventoryType.Currency => session.ServerTableMetadata.ConstantsTable.bagSlotTabCoinCount[0], + InventoryType.Badge => session.ServerTableMetadata.ConstantsTable.bagSlotTabBadgeCount[0], + InventoryType.Lapenshard => session.ServerTableMetadata.ConstantsTable.bagSlotTabLapenShardCount[0], + InventoryType.Fragment => session.ServerTableMetadata.ConstantsTable.bagSlotTabPieceCount[0], _ => throw new ArgumentOutOfRangeException($"Invalid InventoryType: {type}"), }; } - private static short MaxExpandSize(InventoryType type) { + private short MaxExpandSize(InventoryType type) { return type switch { - InventoryType.Gear => Constant.BagSlotTabGameCountMax, - InventoryType.Outfit => Constant.BagSlotTabSkinCountMax, - InventoryType.Mount => Constant.BagSlotTabSummonCountMax, - InventoryType.Catalyst => Constant.BagSlotTabMaterialCountMax, - InventoryType.FishingMusic => Constant.BagSlotTabLifeCountMax, - InventoryType.Quest => Constant.BagSlotTabQuestCountMax, - InventoryType.Gemstone => Constant.BagSlotTabGemCountMax, - InventoryType.Misc => Constant.BagSlotTabMiscCountMax, - InventoryType.LifeSkill => Constant.BagSlotTabMasteryCountMax, - InventoryType.Pets => Constant.BagSlotTabPetCountMax, - InventoryType.Consumable => Constant.BagSlotTabActiveSkillCountMax, - InventoryType.Currency => Constant.BagSlotTabCoinCountMax, - InventoryType.Badge => Constant.BagSlotTabBadgeCountMax, - InventoryType.Lapenshard => Constant.BagSlotTabLapenshardCountMax, - InventoryType.Fragment => Constant.BagSlotTabPieceCountMax, + InventoryType.Gear => session.ServerTableMetadata.ConstantsTable.bagSlotTabGameCount[1], + InventoryType.Outfit => session.ServerTableMetadata.ConstantsTable.bagSlotTabSkinCount[1], + InventoryType.Mount => session.ServerTableMetadata.ConstantsTable.bagSlotTabSummonCount[1], + InventoryType.Catalyst => session.ServerTableMetadata.ConstantsTable.bagSlotTabMaterialCount[1], + InventoryType.FishingMusic => session.ServerTableMetadata.ConstantsTable.bagSlotTabLifeCount[1], + InventoryType.Quest => session.ServerTableMetadata.ConstantsTable.bagSlotTabQuestCount[1], + InventoryType.Gemstone => session.ServerTableMetadata.ConstantsTable.bagSlotTabGemCount[1], + InventoryType.Misc => session.ServerTableMetadata.ConstantsTable.bagSlotTabMiscCount[1], + InventoryType.LifeSkill => session.ServerTableMetadata.ConstantsTable.bagSlotTabMasteryCount[1], + InventoryType.Pets => session.ServerTableMetadata.ConstantsTable.bagSlotTabPetCount[1], + InventoryType.Consumable => session.ServerTableMetadata.ConstantsTable.bagSlotTabActiveSkillCount[1], + InventoryType.Currency => session.ServerTableMetadata.ConstantsTable.bagSlotTabCoinCount[1], + InventoryType.Badge => session.ServerTableMetadata.ConstantsTable.bagSlotTabBadgeCount[1], + InventoryType.Lapenshard => session.ServerTableMetadata.ConstantsTable.bagSlotTabLapenShardCount[1], + InventoryType.Fragment => session.ServerTableMetadata.ConstantsTable.bagSlotTabPieceCount[1], _ => throw new ArgumentOutOfRangeException($"Invalid InventoryType: {type}"), }; } From dff14e7bb686812168b98617f9d83d3b2d9a2107 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Sun, 1 Mar 2026 21:55:44 -0600 Subject: [PATCH 08/26] Update the constant parsing to make it more efficient by removing the nested foreach loop and indexing the property names to search them later when looping through the parsed XML constants data. --- .../Mapper/ServerTableMapper.cs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs index 2818ebe62..b43896b57 100644 --- a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs +++ b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs @@ -16,6 +16,7 @@ using System.Numerics; using System.Reflection; using System.Xml; +using Maple2.File.Parser.Xml.Table; using DayOfWeek = System.DayOfWeek; using ExpType = Maple2.Model.Enum.ExpType; using Fish = Maple2.File.Parser.Xml.Table.Server.Fish; @@ -2117,16 +2118,18 @@ void AddSpecial(Dictionary values, Dictionary propertyLookup = typeof(ConstantsTable).GetProperties() + .ToDictionary(p => p.Name.Trim(), p => p, StringComparer.OrdinalIgnoreCase); + + foreach ((string key, Constants.Key constant) in parser.ParseConstants()) { + string trimmedKey = key.Trim(); + if (!propertyLookup.TryGetValue(trimmedKey, out PropertyInfo? property)) continue; + string cleanValue = CleanConstantsInput( + constant.value.Trim(), + trimmedKey, + property.PropertyType + ); + SetValue(property, constants, cleanValue); } return constants; } From 5d6f08745f43c26bf17be70bfea57c24408abd35 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Sun, 1 Mar 2026 22:55:58 -0600 Subject: [PATCH 09/26] Correct some misspelt property names in ConstantsTable record to allow them to retrieve their values. --- Maple2.Model/Metadata/Constants.cs | 3 ++ .../Metadata/ServerTable/ConstantsTable.cs | 50 +++++++++---------- Maple2.Server.Game/Manager/FishingManager.cs | 2 +- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/Maple2.Model/Metadata/Constants.cs b/Maple2.Model/Metadata/Constants.cs index c609ce3f1..de0408079 100644 --- a/Maple2.Model/Metadata/Constants.cs +++ b/Maple2.Model/Metadata/Constants.cs @@ -293,6 +293,9 @@ public static class Constant { "http://maplestory2.nexon.net/en/news/article/32249/mushking-royale-championship-rewards"; public const int HoldAttackSkillID = 10700252; public const string DiscordAppID = "555204064091045904"; + public const int GuildFundMax = 20000; + public const int DropIconVisibleDistance = 400; + public const string MesoMarketTokenDetailUrl = "http://maplestory2.nexon.net/en/news/article/45213"; #endregion } diff --git a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs index 7eb6b6870..7da1b856f 100644 --- a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs +++ b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs @@ -31,7 +31,6 @@ public record ConstantsTable( int DamageDistance = 0, int TalkableDistance = 0, bool TalkableFrontOnly = false, - int DropIconVisibleDistance = 0, int ChatBalloonDistance = 0, int HpBarDistance = 0, int EmoticonVisibleDistance = 0, @@ -50,7 +49,7 @@ public record ConstantsTable( TimeSpan UgcHomeSaleWaitingTime = new(), int UgcContainerExpireDurationNormal = 0, int UgcContainerExpireDurationCash = 0, - int UgcContainerExpireDurationMeret = 0, + int UgcContainerExpireDurationMerat = 0, int UgcHomeExtensionNoticeDate = 0, int UgcHomePasswordExpireDuration = 0, bool CubeLiftHeightLimitUp = false, @@ -69,17 +68,17 @@ public record ConstantsTable( int DropItemPickUpCompleteRotateVel = 0, int ChatBalloonDuration = 0, int BoreWaitingTick = 0, - int OffsetPcHpBar = 0, - int OffsetPcNameTag = 0, - int OffsetPcChatBalloon = 0, - int OffsetPcDamageNumber = 0, + int OffsetPcHpbar = 0, + int OffsetPcNametag = 0, + int OffsetPcChatballoon = 0, + int OffsetPcDamagenumber = 0, int OffsetPcProfileTag = 0, float fOffsetOnTombstoneNameTag = 0f, int OffsetNpcHpBar = 0, - int OffsetNpcNameTag = 0, + int OffsetNpcNametag = 0, int OffsetNpcEmoticon = 0, int OffsetNpcChatBalloon = 0, - int OffsetNpcDamageNumber = 0, + int OffsetNpcDamagenumber = 0, int OffsetNpcMonologue = 0, int OffsetActionTooltipX = 0, int OffsetActionTooltipY = 0, @@ -113,7 +112,7 @@ public record ConstantsTable( int MonologueShowTime = 0, int ShowKillCountMin = 0, int UserRevivalInvincibleTick = 0, - int UserRevivalPenaltyPercent = 0, + int UserRevivalPaneltyPercent = 0, string UserRevivalIconPath = "", string UserRevivalInvincibleIconPath = "", int GetExpMinVelocity = 0, @@ -149,13 +148,13 @@ public record ConstantsTable( float VolumePcToBreakableObject = 0f, float VolumeNpcToPc = 0f, float VolumeOtherPc = 0f, - int ItemDropLevelMaxBoundary = 0, + int ItemDropLevelMaxBoundry = 0, float moneyTreeDropHeight = 0f, float moneyTreeDropBase = 0f, int moneyTreeDropRandom = 0, - int WhisperIgnoreTime = 0, - int WhisperMaxCount = 0, - int WhisperDurationTime = 0, + int WisperIgnoreTime = 0, + int WisperMaxCount = 0, + int WisperDurationTime = 0, float BossHpBarAutoDetectRange = 0f, float BossHpBarDuration = 0f, float FindHoldTargetRange = 0f, @@ -213,7 +212,7 @@ public record ConstantsTable( float TimeScalePCDuration = 0f, int GoToHomeCastingTime = 0, int returnHomeSkill = 0, - int returnHomeSkillMeret = 0, + int returnHomeSkillMerat = 0, int TutorialIntroSkipTime = 0, int[] AvatarDefaultItemMale = null!, int[] AvatarDefaultItemFemale = null!, @@ -223,10 +222,10 @@ public record ConstantsTable( int UGCShopSellMinPrice = 0, int UGCShopSellMaxPrice = 0, int UGCShopSaleDay = 0, - int UGCShopAdFeeMeret = 0, + int UGCShopAdFeeMerat = 0, int UGCShopAdHour = 0, int UGCShopSellingRestrictAmount = 0, - int MeretMarketHomeBannerShowTick = 0, + int MeratMarketHomeBannerShowTick = 0, long BlackMarketSellMinPrice = 0, long BlackMarketSellMaxPrice = 0, int BlackMarketSellEndDay = 0, @@ -248,7 +247,6 @@ public record ConstantsTable( int GuildCreateMinLevel = 0, int GuildNameLengthMin = 0, int GuildNameLengthMax = 0, - int guildFundMax = 0, float guildFundRate = 0f, int guildExpMaxCountForPlayTime = 0, int guildDonateMeso = 0, @@ -498,7 +496,7 @@ public record ConstantsTable( int NoticeDialogOpenSeconds = 0, int RemakeOptionMaxCount = 0, int fishFightingProp = 0, - int FisherBoreDuration = 0, + int fisherBoreDuration = 0, string fishingStartCastingBarText0 = "", string fishingStartCastingBarText1 = "", string fishingStartCastingBarText2 = "", @@ -569,7 +567,6 @@ public record ConstantsTable( int MesoMarketProductUnit9 = 0, int MesoMarketBuyPayType = 0, int MesoMarketIconType = 0, - string MesoMarketTokenDetailUrl = "", int BeautyHairShopGotoFieldID = 0, int BeautyHairShopGotoPortalID = 0, int BeautyColorShopGotoFieldID = 0, @@ -587,7 +584,7 @@ public record ConstantsTable( int TencentCashChargeWebPageWidth = 0, int TencentCashChargeWebPageHight = 0, int NxaCashChargeWebPageWidth = 0, - int NxaCashChargeWebPageHeight = 0, + int NxaCashChargeWebPageHight = 0, int ItemUnLockTime = 0, int PropertyProtectionTime = 0, string TencentSecurityWebPage = "", @@ -616,7 +613,7 @@ public record ConstantsTable( int ResetShadowBuffMerat = 0, int InventoryExpandPrice1Row = 0, int VIPServicePeriodLimitDay = 0, - int VIPMarketCommissionSale = 0, + int VIPMarketCommitionSale = 0, int DungeonMatchNormalTimeOutTick = 0, int ChaosDungeonHallFieldID = 0, int ReverseRaidDungeonHallFieldID = 0, @@ -740,9 +737,9 @@ public record ConstantsTable( int EnchantTransformScriptID = 0, float AutoHideGroupAlpha = 0f, int AutoHideGroupHitVisibleTick = 0, - int UgcShopCharRotateStartDegreeY = 0, - int UgcShopCharRotateEndDegreeY = 0, - int TreeWateringEmotion = 0, + int UgcshopCharRotateStartDegreeY = 0, + int UgcshopCharRotateEndDegreeY = 0, + int TreewateringEmotion = 0, string ShopProbInfoUrl = "", int AdventureLevelLimit = 0, int AdventureLevelLvUpExp = 0, @@ -817,7 +814,7 @@ public record ConstantsTable( int AdventureLevelMissionResetWeekday = 0, int ItemBoxMultiOpenMaxCount = 0, int ItemBoxMultiOpenLimitCount = 0, - int BuffBalloonDistance = 0, + int BuffBallonDistance = 0, int PaybackStartDate = 0, int PaybackSettleMinutes = 0, int PaybackMarketProductSnList = 0, @@ -864,6 +861,5 @@ public record ConstantsTable( int PvpOnePunchUserOpenRewardItem = 0, string TencentCharacterCreateShutdownLeft = "", string TencentCharacterCreateShutdownRight = "", - int LeadSkillMaxSlot = 0, - int NextStateTriggerDefaultTick = 0 + int LeadSkillMaxSlot = 0 ) : ServerTable; diff --git a/Maple2.Server.Game/Manager/FishingManager.cs b/Maple2.Server.Game/Manager/FishingManager.cs index aeffa3c3e..46be60b03 100644 --- a/Maple2.Server.Game/Manager/FishingManager.cs +++ b/Maple2.Server.Game/Manager/FishingManager.cs @@ -239,7 +239,7 @@ public FishingError Start(Vector3 position) { selectedFish = fishes.Get(); - int fishingTick = session.ServerTableMetadata.ConstantsTable.FisherBoreDuration; + int fishingTick = session.ServerTableMetadata.ConstantsTable.fisherBoreDuration; bool hasAutoFish = session.Player.Buffs.HasBuff(BuffEventType.AutoFish); // Fishing Success From a31f930ef3437e181a31515d16662c7fac80d230 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Mon, 2 Mar 2026 16:24:33 -0600 Subject: [PATCH 10/26] Add Xml.m2d constants.xml within the Server.m2d constants.xml parsing for ConstantsTable. --- Maple2.Model/Metadata/Constants.cs | 98 ------------------- .../Metadata/ServerTable/ConstantsTable.cs | 98 ++++++++++++++++++- Maple2.Server.Game/Commands/PlayerCommand.cs | 4 +- .../Manager/ExperienceManager.cs | 2 +- .../PacketHandlers/QuestHandler.cs | 2 +- .../PacketHandlers/TaxiHandler.cs | 4 +- 6 files changed, 102 insertions(+), 106 deletions(-) diff --git a/Maple2.Model/Metadata/Constants.cs b/Maple2.Model/Metadata/Constants.cs index de0408079..e10fdc17d 100644 --- a/Maple2.Model/Metadata/Constants.cs +++ b/Maple2.Model/Metadata/Constants.cs @@ -130,8 +130,6 @@ public static class Constant { public const int UGCShopProfitDelayDays = 10; public const int PartyFinderListingsPageCount = 12; public const int ProposalItemId = 11600482; - public const int bagSlotTabPetEquipCount = 48; - public const int MeretAirTaxiPrice = 15; public const int ClubMaxCount = 3; public static IReadOnlyDictionary ContentRewards { get; } = new Dictionary { @@ -201,102 +199,6 @@ public static class Constant { public static readonly bool BlockLoginWithMismatchedMachineId = false; public static readonly int DefaultMaxCharacters = 4; #endregion - - #region XML table/constants.xml - public const float NPCCliffHeight = 50.0f; - public const float CustomizingRotationSpeed = 75.0f; - public const bool AllowComboAtComboPoint = true; - public const int AttackRotationSpeed = 90; - public const int ChaosModeTime = 20; - public const int ChaosPointPerBlock = 20; - public const int ChaosPointMaxBlock = 1; - public const int ChaosPointGetLevel0 = 1; - public const int ChaosPointGetPoint0 = 120; - public const int ChaosActionGetLevel0 = 15; - public const int ChaosActionGetLevel1 = 25; - public const int ChaosActionGetLevel2 = 55; - public const int ChaosActionGetLevel3 = 95; - public const int ChaosActionGetLevel4 = 145; - public const int OnEnterTriggerClientSideOnlyTick = 100; - public const int OnEnterTriggerDefaultTick = 1000; - public const int TalkTimeover = 60000; - public const int DropMoneyActiveProbability = 0; - public const int DropMoneyProbability = 0; - public const int OffsetPcMissionIndicator = 20; - public const int questHideTime = 30; - public const int questIntervalTime = 60; - public const int ShopResetChance = 10; - public const int DashKeyInputDelay = 500; - public const int DashSwimConsumeSP = 20; - public const int DashSwimMoveVel = 2; - public const float Glide_Gravity = 0.0f; - public const float Glide_Height_Limit = 0.0f; - public const float Glide_Horizontal_Accelerate = 0.0f; - public const int Glide_Horizontal_Velocity = 500; - public const float Glide_Vertical_Accelerate = 0.0f; - public const int Glide_Vertical_Velocity = 150; - public const int Glide_Vertical_Vibrate_Amplitude = 300; - public const float Glide_Vertical_Vibrate_Frequency = 1500.0f; - public const bool Glide_Effect = true; - public const string Glide_Effect_Run = "CH/Common/Eff_Fly_Balloon_Run.xml"; - public const string Glide_Effect_Idle = "CH/Common/Eff_Fly_Balloon_Idle.xml"; - public const string Glide_Ani_Idle = "Fly_Idle_A"; - public const string Glide_Ani_Left = "Gliding_Left_A"; - public const string Glide_Ani_Right = "Gliding_Right_A"; - public const string Glide_Ani_Run = "Fly_Run_A"; - public const int ConsumeCritical = 5; - public const int DayToNightTime = 10000; - public const float myPCdayTiming = 0.5f; - public const float myPCNightTiming = 0.5f; - public const float BGMTiming = 0.5f; - public const int dayBaseMinute = 1; - public const int dayMinute = 1439; - public const int nightMinute = 1; - public const int QuestRewardSkillSlotQuestID1 = 1010002; - public const int QuestRewardSkillSlotQuestID2 = 1010003; - public const int QuestRewardSkillSlotQuestID3 = 1010004; - public const int QuestRewardSkillSlotQuestID4 = 1010005; - public const int QuestRewardSkillSlotQuestID5 = 1010010; - public const int QuestRewardSkillSlotItemID1 = 40000000; - public const int QuestRewardSkillSlotItemID2 = 40200001; - public const int QuestRewardSkillSlotItemID3 = 20000001; - public const int QuestRewardSkillSlotItemID4 = 40000055; - public const int QuestRewardSkillSlotItemID5 = 40000056; - public const int autoTargetingMaxDegree = 210; - public const float BossHitVibrateFreq = 10.0f; - public const float BossHitVibrateAmp = 5.5f; - public const float BossHitVibrateDamping = 0.7f; - public const float BossHitVibrateDuration = 0.1f; - public const int OneTimeWeaponItemID = 15000001; - public const int ModelHouse = 62000027; - public const int UsingNoPhysXModelUserCount = 10; - public const int UsingNoPhysXModelActorCount = 10; - public const int UsingNoPhysXModelJointCount = 10; - public const bool EnableSoundMute = true; - public const int BossKillSoundRange = 1500; - public const int monsterPeakTimeNotifyDuration = 300; - public const int AirTaxiItemID = 20300003; - public const int ShowNameTagSellerTitle = 10000153; - public const int ShowNameTagChampionTitle = 10000152; - public const int ShowNameTagTrophy1000Title = 10000170; - public const int ShowNameTagTrophy2000Title = 10000171; - public const int ShowNameTagTrophy3000Title = 10000172; - public const int ShowNameTagArchitectTitle = 10000158; - public const int characterMaxLevel = 99; // Updated - public const int OneShotSkillID = 19900061; - public const int FindDungeonHelpEasyDungeonLevel = 50; - public const int FameContentsRequireQuestID = 91000013; - public const int FameExpedContentsRequireQuestID = 50101050; - public const int SurvivalScanAdditionalID = 71000052; - public const int MapleSurvivalTopNRanking = 5; - public const string MapleSurvivalSeasonRewardUrl = - "http://maplestory2.nexon.net/en/news/article/32249/mushking-royale-championship-rewards"; - public const int HoldAttackSkillID = 10700252; - public const string DiscordAppID = "555204064091045904"; - public const int GuildFundMax = 20000; - public const int DropIconVisibleDistance = 400; - public const string MesoMarketTokenDetailUrl = "http://maplestory2.nexon.net/en/news/article/45213"; - #endregion } #pragma warning restore IDE1006 // Naming Styles diff --git a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs index 7da1b856f..394888684 100644 --- a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs +++ b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs @@ -552,7 +552,7 @@ public record ConstantsTable( int GuideQuestDailyPickCountBoss = 0, int DailyMissionPickCount = 0, int DailyMissionRequireLevel = 0, - float NearDropDistance =0f, + float NearDropDistance = 0f, float FarDropDistance = 0f, int MesoMarketBasePrice = 0, int MesoMarketProductUnit0 = 0, @@ -861,5 +861,99 @@ public record ConstantsTable( int PvpOnePunchUserOpenRewardItem = 0, string TencentCharacterCreateShutdownLeft = "", string TencentCharacterCreateShutdownRight = "", - int LeadSkillMaxSlot = 0 + int LeadSkillMaxSlot = 0, + float NPCCliffHeight = 0f, + float CustomizingRotationSpeed = 0f, + bool AllowComboAtComboPoint = false, + int AttackRotationSpeed = 0, + int ChaosModeTime = 0, + int ChaosPointPerBlock = 0, + int ChaosPointMaxBlock = 0, + int ChaosPointGetLevel0 = 0, + int ChaosPointGetPoint0 = 0, + int ChaosActionGetLevel0 = 0, + int ChaosActionGetLevel1 = 0, + int ChaosActionGetLevel2 = 0, + int ChaosActionGetLevel3 = 0, + int ChaosActionGetLevel4 = 0, + int OnEnterTriggerClientSideOnlyTick = 0, + int OnEnterTriggerDefaultTick = 0, + int TalkTimeover = 0, + int DropIconVisibleDistance = 0, + int DropMoneyActiveProbability = 0, + int DropMoneyProbability = 0, + int OffsetPcMissionIndicator = 0, + int questHideTime = 0, + int questIntervalTime = 0, + int ShopResetChance = 0, + int DashKeyInputDelay = 0, + int DashSwimConsumeSP = 0, + int DashSwimMoveVel = 0, + float Glide_Gravity = 0f, + float Glide_Height_Limit = 0f, + float Glide_Horizontal_Accelerate = 0f, + int Glide_Horizontal_Velocity = 0, + float Glide_Vertical_Accelerate = 0f, + int Glide_Vertical_Velocity = 0, + int Glide_Vertical_Vibrate_Amplitude = 0, + float Glide_Vertical_Vibrate_Frequency = 0f, + bool Glide_Effect = false, + string Glide_Effect_Run = "", + string Glide_Effect_Idle = "", + string Glide_Ani_Idle = "", + string Glide_Ani_Left = "", + string Glide_Ani_Right = "", + string Glide_Ani_Run = "", + int ConsumeCritical = 0, + int DayToNightTime = 0, + float myPCdayTiming = 0f, + float myPCNightTiming = 0f, + float BGMTiming = 0f, + int dayBaseMinute = 0, + int dayMinute = 0, + int nightMinute = 0, + int QuestRewardSkillSlotQuestID1 = 0, + int QuestRewardSkillSlotQuestID2 = 0, + int QuestRewardSkillSlotQuestID3 = 0, + int QuestRewardSkillSlotQuestID4 = 0, + int QuestRewardSkillSlotQuestID5 = 0, + int QuestRewardSkillSlotItemID1 = 0, + int QuestRewardSkillSlotItemID2 = 0, + int QuestRewardSkillSlotItemID3 = 0, + int QuestRewardSkillSlotItemID4 = 0, + int QuestRewardSkillSlotItemID5 = 0, + int autoTargetingMaxDegree = 0, + float BossHitVibrateFreq = 0f, + float BossHitVibrateAmp = 0f, + float BossHitVibrateDamping = 0f, + float BossHitVibrateDuration = 0f, + int OneTimeWeaponItemID = 0, + int ModelHouse = 0, + int UsingNoPhysXModelUserCount = 0, + int UsingNoPhysXModelActorCount = 0, + int UsingNoPhysXModelJointCount = 0, + int guildFundMax = 0, + bool EnableSoundMute = false, + int BossKillSoundRange = 0, + int monsterPeakTimeNotifyDuration = 0, + int AirTaxiItemID = 0, + int ShowNameTagSellerTitle = 0, + int ShowNameTagChampionTitle = 0, + int ShowNameTagTrophy1000Title = 0, + int ShowNameTagTrophy2000Title = 0, + int ShowNameTagTrophy3000Title = 0, + int ShowNameTagArchitectTitle = 0, + int characterMaxLevel = 0, + string MesoMarketTokenDetailUrl = "", + int OneShotSkillID = 0, + short[] bagSlotTabPetEquipCount = null!, + int MeratAirTaxiPrice = 0, + int FindDungeonHelpEasyDungeonLevel = 0, + int FameContentsRequireQuestID = 0, + int FameExpedContentsRequireQuestID = 0, + int SurvivalScanAdditionalID = 0, + int MapleSurvivalTopNRanking = 0, + string MapleSurvivalSeasonRewardUrl = "", + int HoldAttackSkillID = 0, + string DiscordAppID = "" ) : ServerTable; diff --git a/Maple2.Server.Game/Commands/PlayerCommand.cs b/Maple2.Server.Game/Commands/PlayerCommand.cs index ff4f419d6..6ceef9728 100644 --- a/Maple2.Server.Game/Commands/PlayerCommand.cs +++ b/Maple2.Server.Game/Commands/PlayerCommand.cs @@ -127,8 +127,8 @@ public LevelCommand(GameSession session) : base("level", "Set player level.") { private void Handle(InvocationContext ctx, short level) { try { - if (level is < 1 or > Constant.characterMaxLevel) { - ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {Constant.characterMaxLevel}."); + if (level < 1 || level > session.ServerTableMetadata.ConstantsTable.characterMaxLevel) { + ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {session.ServerTableMetadata.ConstantsTable.characterMaxLevel}."); return; } diff --git a/Maple2.Server.Game/Manager/ExperienceManager.cs b/Maple2.Server.Game/Manager/ExperienceManager.cs index e733c0dac..52985f35a 100644 --- a/Maple2.Server.Game/Manager/ExperienceManager.cs +++ b/Maple2.Server.Game/Manager/ExperienceManager.cs @@ -175,7 +175,7 @@ public void AddMobExp(int moblevel, float modifier = 1f, long additionalExp = 0) public bool LevelUp() { int startLevel = Level; - for (int level = startLevel; level < Constant.characterMaxLevel; level++) { + for (int level = startLevel; level < session.ServerTableMetadata.ConstantsTable.characterMaxLevel; level++) { if (!session.TableMetadata.ExpTable.NextExp.TryGetValue(level, out long expToNextLevel) || expToNextLevel > Exp) { break; } diff --git a/Maple2.Server.Game/PacketHandlers/QuestHandler.cs b/Maple2.Server.Game/PacketHandlers/QuestHandler.cs index 9da442bb9..a23b4ba12 100644 --- a/Maple2.Server.Game/PacketHandlers/QuestHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/QuestHandler.cs @@ -266,7 +266,7 @@ private static void HandleCompleteFieldMission(GameSession session, IByteReader } private static void HandleSkyFortressTeleport(GameSession session) { - if (!session.Quest.TryGetQuest(Constant.FameContentsRequireQuestID, out Quest? quest) || quest.State != QuestState.Completed) { + if (!session.Quest.TryGetQuest(session.ServerTableMetadata.ConstantsTable.FameContentsRequireQuestID, out Quest? quest) || quest.State != QuestState.Completed) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs b/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs index 7c62abf4a..5d8e8277a 100644 --- a/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs @@ -136,12 +136,12 @@ private void HandleMeretAirTaxi(GameSession session, IByteReader packet) { return; } - if (session.Currency.Meret < Constant.MeretAirTaxiPrice) { + if (session.Currency.Meret < session.ServerTableMetadata.ConstantsTable.MeratAirTaxiPrice) { session.Send(NoticePacket.MessageBox(StringCode.s_err_lack_meso)); return; } - session.Currency.Meret -= Constant.MeretAirTaxiPrice; + session.Currency.Meret -= session.ServerTableMetadata.ConstantsTable.MeratAirTaxiPrice; session.Send(session.PrepareField(mapId) ? FieldEnterPacket.Request(session.Player) From d1c3b138100714cc2500aa9a16298f15371f62bc Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Mon, 2 Mar 2026 16:50:37 -0600 Subject: [PATCH 11/26] Fix a crash at character entering world due to JSON deserialization confusion from two constructors and nethier defined as the JSON constructor. --- Maple2.Model/Metadata/NpcMetadata.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Maple2.Model/Metadata/NpcMetadata.cs b/Maple2.Model/Metadata/NpcMetadata.cs index 25f7579f7..b3006e77c 100644 --- a/Maple2.Model/Metadata/NpcMetadata.cs +++ b/Maple2.Model/Metadata/NpcMetadata.cs @@ -1,5 +1,6 @@ using System.ComponentModel.Design; using System.Numerics; +using System.Text.Json.Serialization; using Maple2.Model.Enum; namespace Maple2.Model.Metadata; @@ -57,6 +58,7 @@ public record NpcMetadataDistance( float Sight, float SightHeightUp, float SightHeightDown) { + [JsonConstructor] public NpcMetadataDistance(float avoid, float sight, float sightHeightUp, float sightHeightDown, float lastSightRadius, float lastSightHeightUp, float lastSightHeightDown) : this(avoid, sight, sightHeightUp, sightHeightDown) { LastSightRadius = lastSightRadius; From 80ffb235774aa24ca4b8ad6a7d87c4faa7ad843a Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Tue, 3 Mar 2026 09:05:28 -0600 Subject: [PATCH 12/26] Fix changes that were deleted during merge conflict resolution. Added back GlobalCubeSkillIntervalTime and merged into XML parsing functionality, while also adding back NpcMetadataCorpse parameter in NpcMetadata record. --- Maple2.File.Ingest/Mapper/ServerTableMapper.cs | 3 +++ Maple2.Model/Metadata/NpcMetadata.cs | 7 ++++--- Maple2.Model/Metadata/ServerTable/ConstantsTable.cs | 2 +- .../Manager/Field/FieldManager/FieldManager.State.cs | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs index 5f25f5b0f..32bca1ffb 100644 --- a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs +++ b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs @@ -2201,6 +2201,9 @@ private void SetValue(PropertyInfo prop, object? obj, object? value) { if (prop.Name == "DailyTrophyResetDate") { value = ((string)value).Replace('-', ':'); } + if (prop.Name == "GlobalCubeSkillIntervalTime") { + value = $"0:0:{(string) value}"; + } value = TimeSpan.Parse((string)value, CultureInfo.InvariantCulture); } // Handle array types (int[], short[], etc.) diff --git a/Maple2.Model/Metadata/NpcMetadata.cs b/Maple2.Model/Metadata/NpcMetadata.cs index e13c140bb..0615bce1c 100644 --- a/Maple2.Model/Metadata/NpcMetadata.cs +++ b/Maple2.Model/Metadata/NpcMetadata.cs @@ -18,24 +18,25 @@ public record NpcMetadata( NpcMetadataDropInfo DropInfo, NpcMetadataAction Action, NpcMetadataDead Dead, + NpcMetadataCorpse? Corpse, NpcMetadataLookAtTarget LookAtTarget) : ISearchResult { public NpcMetadata(NpcMetadata other, float lastSightRadius) : this(other.Id, other.Name, other.AiPath, other.Model, other.Stat, other.Basic, other.Distance, other.Skill, other.Property, other.DropInfo, - other.Action, other.Dead, other.LookAtTarget) { + other.Action, other.Dead, other.Corpse, other.LookAtTarget) { Distance = new NpcMetadataDistance(Distance.Avoid, Distance.Sight, Distance.SightHeightUp, Distance.SightHeightDown, lastSightRadius, Distance.LastSightHeightUp, Distance.LastSightHeightDown); } public NpcMetadata(NpcMetadata other, float lastSightRadius, float lastSightHeightUp) : this(other.Id, other.Name, other.AiPath, other.Model, other.Stat, other.Basic, other.Distance, other.Skill, other.Property, other.DropInfo, - other.Action, other.Dead, other.LookAtTarget) { + other.Action, other.Dead, other.Corpse, other.LookAtTarget) { Distance = new NpcMetadataDistance(Distance.Avoid, Distance.Sight, Distance.SightHeightUp, Distance.SightHeightDown, lastSightRadius, lastSightHeightUp, Distance.LastSightHeightDown); } public NpcMetadata(NpcMetadata other, float lastSightRadius, float lastSightHeightUp, float lastSightHeightDown) : this(other.Id, other.Name, other.AiPath, other.Model, other.Stat, other.Basic, other.Distance, other.Skill, other.Property, other.DropInfo, - other.Action, other.Dead, other.LookAtTarget) { + other.Action, other.Dead, other.Corpse, other.LookAtTarget) { Distance = new NpcMetadataDistance(Distance.Avoid, Distance.Sight, Distance.SightHeightUp, Distance.SightHeightDown, lastSightRadius, lastSightHeightUp, lastSightHeightDown); } diff --git a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs index 394888684..815e7fe4a 100644 --- a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs +++ b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs @@ -271,7 +271,7 @@ public record ConstantsTable( int HomeReturnPortalKeepTime = 0, string HomeReturnPortalKeepNif = "", int HomeReturnPortalDimensionY = 0, - float GlobalCubeSkillIntervalTime = 0f, + TimeSpan GlobalCubeSkillIntervalTime = new(), int RoomEnterPortalDurationTick = 0, int NpcBossCubeSkillCreateHeight = 0, int NPCUpdateTickNoUser = 0, diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs index d8c204cf2..2897d2211 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs @@ -725,7 +725,7 @@ public void RemoveSkillByTriggerId(int triggerId) { private void AddCubeSkill(SkillMetadata metadata, in Vector3 position, in Vector3 rotation = default) { Vector3 adjustedPosition = position; adjustedPosition.Z += FieldAccelerationStructure.BLOCK_SIZE; - var fieldSkill = new FieldSkill(this, NextLocalId(), FieldActor, metadata, (int) Constant.GlobalCubeSkillIntervalTime.TotalMilliseconds, adjustedPosition) { + var fieldSkill = new FieldSkill(this, NextLocalId(), FieldActor, metadata, (int)ServerTableMetadata.ConstantsTable.GlobalCubeSkillIntervalTime.TotalMilliseconds, adjustedPosition) { Position = adjustedPosition, Rotation = rotation, Source = SkillSource.Cube, From 8adfa4ded0ca9e37341a6c25bff61f92a6d308d2 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Tue, 3 Mar 2026 09:21:42 -0600 Subject: [PATCH 13/26] Took CodeRabbit suggestion since it pointed out unreachable branches and it's much cleaner than what was being used to pass constant values for lasting sight radius, height up, and height down. --- Maple2.Model/Game/Npc/Npc.cs | 13 ++++--------- Maple2.Model/Metadata/NpcMetadata.cs | 14 -------------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/Maple2.Model/Game/Npc/Npc.cs b/Maple2.Model/Game/Npc/Npc.cs index a2c341b3e..fc176815c 100644 --- a/Maple2.Model/Game/Npc/Npc.cs +++ b/Maple2.Model/Game/Npc/Npc.cs @@ -11,15 +11,10 @@ public class Npc { public bool IsBoss => Metadata.Basic.Friendly == 0 && Metadata.Basic.Class >= 3; public Npc(NpcMetadata metadata, AnimationMetadata? animation, float constLastSightRadius, float constLastSightHeightUp, float constLastSightHeightDown) { - if (metadata.Distance.LastSightRadius == 0) { - Metadata = new NpcMetadata(metadata, constLastSightRadius); - } else if (metadata.Distance.LastSightRadius == 0 && metadata.Distance.LastSightHeightUp == 0) { - Metadata = new NpcMetadata(metadata, constLastSightRadius, constLastSightHeightUp); - } else if (metadata.Distance.LastSightRadius == 0 && metadata.Distance.LastSightHeightUp == 0 && metadata.Distance.LastSightHeightDown == 0) { - Metadata = new NpcMetadata(metadata, constLastSightRadius, constLastSightHeightUp, constLastSightHeightDown); - } else { - Metadata = metadata; - } + float lastSightRadius = metadata.Distance.LastSightRadius == 0 ? constLastSightRadius : metadata.Distance.LastSightRadius; + float lastSightHeightUp = metadata.Distance.LastSightHeightUp == 0 ? constLastSightHeightUp : metadata.Distance.LastSightHeightUp; + float lastSightHeightDown = metadata.Distance.LastSightHeightDown == 0 ? constLastSightHeightDown : metadata.Distance.LastSightHeightDown; + Metadata = new NpcMetadata(metadata, lastSightRadius, lastSightHeightUp, lastSightHeightDown); Animations = animation?.Sequences ?? new Dictionary(); } } diff --git a/Maple2.Model/Metadata/NpcMetadata.cs b/Maple2.Model/Metadata/NpcMetadata.cs index 0615bce1c..fca9752e6 100644 --- a/Maple2.Model/Metadata/NpcMetadata.cs +++ b/Maple2.Model/Metadata/NpcMetadata.cs @@ -20,20 +20,6 @@ public record NpcMetadata( NpcMetadataDead Dead, NpcMetadataCorpse? Corpse, NpcMetadataLookAtTarget LookAtTarget) : ISearchResult { - public NpcMetadata(NpcMetadata other, float lastSightRadius) : this(other.Id, - other.Name, other.AiPath, other.Model, other.Stat, other.Basic, other.Distance, other.Skill, other.Property, other.DropInfo, - other.Action, other.Dead, other.Corpse, other.LookAtTarget) { - Distance = new NpcMetadataDistance(Distance.Avoid, Distance.Sight, Distance.SightHeightUp, - Distance.SightHeightDown, lastSightRadius, Distance.LastSightHeightUp, Distance.LastSightHeightDown); - } - - public NpcMetadata(NpcMetadata other, float lastSightRadius, float lastSightHeightUp) : this(other.Id, - other.Name, other.AiPath, other.Model, other.Stat, other.Basic, other.Distance, other.Skill, other.Property, other.DropInfo, - other.Action, other.Dead, other.Corpse, other.LookAtTarget) { - Distance = new NpcMetadataDistance(Distance.Avoid, Distance.Sight, Distance.SightHeightUp, - Distance.SightHeightDown, lastSightRadius, lastSightHeightUp, Distance.LastSightHeightDown); - } - public NpcMetadata(NpcMetadata other, float lastSightRadius, float lastSightHeightUp, float lastSightHeightDown) : this(other.Id, other.Name, other.AiPath, other.Model, other.Stat, other.Basic, other.Distance, other.Skill, other.Property, other.DropInfo, other.Action, other.Dead, other.Corpse, other.LookAtTarget) { From 91ae45ca7e5aa58e5bb7a88acd7bf04b6161d32b Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Tue, 3 Mar 2026 09:31:39 -0600 Subject: [PATCH 14/26] Remove accidental default values from hardcoded constants in ConstantsTable record pointed out by CodeRabbit. --- Maple2.Model/Metadata/ServerTable/ConstantsTable.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs index 815e7fe4a..805078afd 100644 --- a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs +++ b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs @@ -302,7 +302,7 @@ public record ConstantsTable( int RecoveryHPWaitTick = 0, int RecoverySPWaitTick = 0, int RecoveryEPWaitTick = 0, - int timeResetDead = 180, + int timeResetDead = 0, int maxDeadCount = 0, byte hitPerDeadCount = 0, int spawntimePerDeadCount = 0, @@ -322,7 +322,7 @@ public record ConstantsTable( float NpcLastingSightRadius = 0f, float NpcLastingSightHeightUp = 0f, float NpcLastingSightHeightDown = 0f, - int HoldTimeEventTick = 5000, + int HoldTimeEventTick = 0, int OnixItemID = 0, int BindOnixItemID = 0, int ChaosOnixItemID = 0, @@ -395,8 +395,8 @@ public record ConstantsTable( int PvpGuildRewardWinnerCount = 0, int PvpGuildRewardLoserCount = 0, int[] ModePVPRedArenaAdditionalEffect = null!, - int ModePvPScoreDead = -50, - int ModePvPScoreKill = 100, + int ModePvPScoreDead = 0, + int ModePvPScoreKill = 0, int[] ModePVPBloodMineAdditionalEffect = null!, int pvpFFAShortComboTick = 0, int pvpFFALongComboTick = 0, From 9cd72f1b82031d718eb3861529fbad02379fe838 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Tue, 3 Mar 2026 11:01:34 -0600 Subject: [PATCH 15/26] Fix a mismatch of currency being used and currency error message being used found by CodeRabbit. --- Maple2.Server.Game/PacketHandlers/TaxiHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs b/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs index 5d8e8277a..a2db64fef 100644 --- a/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs @@ -137,7 +137,7 @@ private void HandleMeretAirTaxi(GameSession session, IByteReader packet) { } if (session.Currency.Meret < session.ServerTableMetadata.ConstantsTable.MeratAirTaxiPrice) { - session.Send(NoticePacket.MessageBox(StringCode.s_err_lack_meso)); + session.Send(NoticePacket.MessageBox(StringCode.s_err_lack_merat)); return; } From d54d651d7bb41e7df32daafc41d059764e90940a Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Tue, 3 Mar 2026 13:48:00 -0600 Subject: [PATCH 16/26] Replace Parse calls with TryParse to prevent runtime crashes. Additionally, remove Convert.ChangeType usage, create a reflection-based approach to access TryParse for generic objects. --- .../Mapper/ServerTableMapper.cs | 121 +++++++++++++----- 1 file changed, 92 insertions(+), 29 deletions(-) diff --git a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs index 32bca1ffb..50a6a6df3 100644 --- a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs +++ b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs @@ -4,6 +4,7 @@ using Maple2.File.Parser; using Maple2.File.Parser.Enum; using Maple2.File.Parser.Flat.Convert; +using Maple2.File.Parser.Xml.Table; using Maple2.File.Parser.Xml.Table.Server; using Maple2.Model; using Maple2.Model.Common; @@ -12,11 +13,11 @@ using Maple2.Model.Game; using Maple2.Model.Game.Shop; using Maple2.Model.Metadata; +using Newtonsoft.Json.Linq; using System.Globalization; using System.Numerics; using System.Reflection; using System.Xml; -using Maple2.File.Parser.Xml.Table; using DayOfWeek = System.DayOfWeek; using ExpType = Maple2.Model.Enum.ExpType; using Fish = Maple2.File.Parser.Xml.Table.Server.Fish; @@ -2167,21 +2168,36 @@ private string CleanConstantsInput(string input, string propName, Type type) { if (type == typeof(float) && input.Contains('f')) { input = input.TrimEnd('f', 'F'); } - // 1 does not automatically equate to true during bool conversion - if (type == typeof(bool) && input == "1") { - input = "true"; - } - // 0 does not automatically equate to false during bool conversion - if (type == typeof(bool) && input == "0") { - input = "false"; + if (type == typeof(bool)) { + // 1 does not automatically equate to true during bool conversion + if (input == "1") { + input = "true"; + } + // 0 does not automatically equate to false during bool conversion + if (input == "0") { + input = "false"; + } } - // Convert into a TimeSpan friendly input string instead of an int value - if (type == typeof(TimeSpan) && propName == "UgcHomeSaleWaitingTime") { - input = TimeSpan.FromSeconds(int.Parse(input)).ToString(); // TODO: may not be correct conversion to TimeSpan + if (type == typeof(TimeSpan)) { + // Special case - dashes (-) are used instead of colons (:) + if (propName == "DailyTrophyResetDate") { + input = input.Replace('-', ':'); + } + // Stored as 0.1 for 100ms + if (propName == "GlobalCubeSkillIntervalTime") { + input = $"0:0:{input}"; + } + // Stored as an int value, convert to friendly input string for TimeSpan parsing + if (propName == "UgcHomeSaleWaitingTime") { + int.TryParse(input, out int result); + input = TimeSpan.FromSeconds(result).ToString(); // TODO: may not be correct conversion to TimeSpan + } } - // Remove prefix 0 on integers since they do not convert properly - if (type == typeof(int) && input[0] == '0' && input.Length > 1) { - input = input.Remove(0, 1); + if (type == typeof(int)) { + // Remove prefix 0 on integers since they do not convert properly + if (input.Length > 1 && input[0] == '0') { + input = input.Remove(0, 1); + } } return input; } @@ -2189,22 +2205,21 @@ private string CleanConstantsInput(string input, string propName, Type type) { private void SetValue(PropertyInfo prop, object? obj, object? value) { if (obj == null && value == null || value == null) return; HandleNonIConvertibleTypes(prop, ref value); - bool isConvertible = typeof(IConvertible).IsAssignableFrom(prop.PropertyType); - prop.SetValue(obj, isConvertible ? Convert.ChangeType(value, prop.PropertyType, CultureInfo.InvariantCulture) : value); + if (value == null) return; + if (typeof(IConvertible).IsAssignableFrom(prop.PropertyType)) { + TryParseObject(prop.PropertyType, value, out object? result); + prop.SetValue(obj, result); + return; + } + prop.SetValue(obj, value); } private object? HandleNonIConvertibleTypes(PropertyInfo prop, ref object? value) { if (value == null) return value; // Handle TimeSpan type if (prop.PropertyType == typeof(TimeSpan)) { - // Special case - dashes (-) are used instead of colons (:) - if (prop.Name == "DailyTrophyResetDate") { - value = ((string)value).Replace('-', ':'); - } - if (prop.Name == "GlobalCubeSkillIntervalTime") { - value = $"0:0:{(string) value}"; - } - value = TimeSpan.Parse((string)value, CultureInfo.InvariantCulture); + TimeSpan.TryParse((string) value, CultureInfo.InvariantCulture, out TimeSpan val); + value = val; } // Handle array types (int[], short[], etc.) if (prop.PropertyType.IsArray) { @@ -2213,8 +2228,8 @@ private void SetValue(PropertyInfo prop, object? obj, object? value) { string[] segments = ((string)value).Split(','); Array destinationArray = Array.CreateInstance(elementType, segments.Length); for (int i = 0; i < segments.Length; i++) { - object convertedValue = Convert.ChangeType(segments[i].Trim(), elementType); - destinationArray.SetValue(convertedValue, i); + TryParseObject(elementType, segments[i].Trim(), out object? parseResult); + destinationArray.SetValue(parseResult ?? default, i); } value = destinationArray; } @@ -2222,10 +2237,58 @@ private void SetValue(PropertyInfo prop, object? obj, object? value) { if (prop.PropertyType == typeof(Vector3)) { string[] parts = ((string) value).Split(','); if (parts.Length != 3) return value; - value = new Vector3(float.Parse(parts[0], CultureInfo.InvariantCulture), - float.Parse(parts[1], CultureInfo.InvariantCulture), - float.Parse(parts[2], CultureInfo.InvariantCulture)); + float.TryParse(parts[0], CultureInfo.InvariantCulture, out float x); + float.TryParse(parts[1], CultureInfo.InvariantCulture, out float y); + float.TryParse(parts[2], CultureInfo.InvariantCulture, out float z); + value = new Vector3(x, y, z); } return value; } + + private bool TryParseObject(Type? elementType, object? input, out object? result) { + if (elementType == null || input == null) { + result = null; + return false; + } + + string? inputString = Convert.ToString(input, CultureInfo.InvariantCulture); + + // No TryParse method exists for a string, use the result directly. + if (elementType == typeof(string)) { + result = inputString; + return true; + } + + Type[] argTypes = { + typeof(string), + typeof(IFormatProvider), + elementType.MakeByRefType() + }; + + var method = elementType.GetMethod("TryParse", + BindingFlags.Public | BindingFlags.Static, + null, argTypes, null); + if (method != null) { + object[] args = [inputString, CultureInfo.InvariantCulture, null]; + bool success = (bool)method.Invoke(null, args); + result = args[2]; + return success; + } + + // Fallback without CulturueInfo provided, in case the type does not have a CultureInfo overload. + Type[] simpleArgs = { typeof(string), elementType.MakeByRefType() }; + method = elementType.GetMethod("TryParse", + BindingFlags.Public | BindingFlags.Static, + null, simpleArgs, null); + if (method != null) { + object[] args = { inputString, null }; + bool success = (bool) method.Invoke(null, args); + result = args[1]; + return success; + } + + + result = null; + return false; + } } From a8e748bfccce4ac69627cddd48c7b994c9cec90c Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Tue, 3 Mar 2026 15:26:08 -0600 Subject: [PATCH 17/26] Changes per feedback from Zin --- Maple2.Server.Game/Commands/PlayerCommand.cs | 13 ++-- .../Manager/BlackMarketManager.cs | 4 +- Maple2.Server.Game/Manager/BuddyManager.cs | 8 ++- Maple2.Server.Game/Manager/ConfigManager.cs | 16 +++-- Maple2.Server.Game/Manager/CurrencyManager.cs | 43 ++++++------ .../Manager/ExperienceManager.cs | 24 +++---- .../Field/FieldManager/FieldManager.State.cs | 20 +++--- .../Field/FieldManager/FieldManager.cs | 5 +- Maple2.Server.Game/Manager/FishingManager.cs | 6 +- .../Manager/ItemMergeManager.cs | 4 +- .../Manager/Items/InventoryManager.cs | 66 ++++++++++--------- .../Manager/Items/StorageManager.cs | 7 +- Maple2.Server.Game/Manager/SkillManager.cs | 6 +- Maple2.Server.Game/Manager/TradeManager.cs | 10 +-- .../MovementState.CleanupTask.cs | 7 +- .../Model/Field/Actor/FieldPet.cs | 6 +- .../Model/Field/Actor/FieldPlayer.cs | 10 +-- Maple2.Server.Game/Model/Field/Tombstone.cs | 6 +- .../PacketHandlers/BeautyHandler.cs | 23 +++---- .../PacketHandlers/ClubHandler.cs | 7 +- .../PacketHandlers/GuildHandler.cs | 11 ++-- .../PacketHandlers/HomeBankHandler.cs | 17 ++++- .../PacketHandlers/HomeDoctorHandler.cs | 16 ++++- .../PacketHandlers/ItemLockHandler.cs | 18 +++-- .../PacketHandlers/JobHandler.cs | 17 ++++- .../PacketHandlers/MeretMarketHandler.cs | 13 ++-- .../PacketHandlers/MesoMarketHandler.cs | 20 ++++-- .../PacketHandlers/NpcTalkHandler.cs | 5 +- .../PacketHandlers/PartyHandler.cs | 7 +- .../PacketHandlers/QuestHandler.cs | 13 ++-- .../PacketHandlers/SystemShopHandler.cs | 21 ++++-- .../PacketHandlers/TaxiHandler.cs | 7 +- .../PacketHandlers/UserChatHandler.cs | 7 +- Maple2.Server.Game/Session/GameSession.cs | 6 +- .../CharacterManagementHandler.cs | 14 ++-- Maple2.Server.World/Containers/PartyLookup.cs | 13 ++-- Maple2.Server.World/Program.cs | 2 - Maple2.Server.World/WorldServer.cs | 6 +- 38 files changed, 310 insertions(+), 194 deletions(-) diff --git a/Maple2.Server.Game/Commands/PlayerCommand.cs b/Maple2.Server.Game/Commands/PlayerCommand.cs index 6ceef9728..7140cb035 100644 --- a/Maple2.Server.Game/Commands/PlayerCommand.cs +++ b/Maple2.Server.Game/Commands/PlayerCommand.cs @@ -115,6 +115,7 @@ private void Handle(InvocationContext ctx, MasteryType masteryType, int level) { private class LevelCommand : Command { private readonly GameSession session; + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; public LevelCommand(GameSession session) : base("level", "Set player level.") { this.session = session; @@ -127,8 +128,8 @@ public LevelCommand(GameSession session) : base("level", "Set player level.") { private void Handle(InvocationContext ctx, short level) { try { - if (level < 1 || level > session.ServerTableMetadata.ConstantsTable.characterMaxLevel) { - ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {session.ServerTableMetadata.ConstantsTable.characterMaxLevel}."); + if (level < 1 || level > Constants.characterMaxLevel) { + ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {Constants.characterMaxLevel}."); return; } @@ -180,6 +181,7 @@ private void Handle(InvocationContext ctx, long exp) { private class PrestigeCommand : Command { private readonly GameSession session; + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; public PrestigeCommand(GameSession session) : base("prestige", "Sets prestige level") { this.session = session; @@ -191,8 +193,8 @@ public PrestigeCommand(GameSession session) : base("prestige", "Sets prestige le private void Handle(InvocationContext ctx, int level) { try { - if (level < 1 || level > session.ServerTableMetadata.ConstantsTable.AdventureLevelLimit) { - ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {session.ServerTableMetadata.ConstantsTable.AdventureLevelLimit}."); + if (level < 1 || level > Constants.AdventureLevelLimit) { + ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {Constants.AdventureLevelLimit}."); return; } @@ -209,6 +211,7 @@ private void Handle(InvocationContext ctx, int level) { private class JobCommand : Command { private readonly GameSession session; + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; public JobCommand(GameSession session) : base("job", "Set player job.") { this.session = session; @@ -328,7 +331,7 @@ private void JobAdvance(Job job) { session.Player.Buffs.Clear(); session.Player.Buffs.Initialize(); - session.Player.Buffs.LoadFieldBuffs(session.ServerTableMetadata.ConstantsTable.shadowWorldBuffHpUp, session.ServerTableMetadata.ConstantsTable.shadowWorldBuffMoveProtect); + session.Player.Buffs.LoadFieldBuffs(Constants.shadowWorldBuffHpUp, Constants.shadowWorldBuffMoveProtect); session.Stats.Refresh(); session.Field?.Broadcast(JobPacket.Advance(session.Player, session.Config.Skill.SkillInfo)); } diff --git a/Maple2.Server.Game/Manager/BlackMarketManager.cs b/Maple2.Server.Game/Manager/BlackMarketManager.cs index 5086c8a40..ab3fcacf2 100644 --- a/Maple2.Server.Game/Manager/BlackMarketManager.cs +++ b/Maple2.Server.Game/Manager/BlackMarketManager.cs @@ -16,6 +16,8 @@ namespace Maple2.Server.Game.Manager; public sealed class BlackMarketManager { private readonly GameSession session; + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + private readonly ILogger logger = Log.Logger.ForContext(); public BlackMarketManager(GameSession session) { @@ -63,7 +65,7 @@ public void Add(long itemUid, long price, int quantity) { AccountId = session.AccountId, CharacterId = session.CharacterId, Deposit = depositFee, - ExpiryTime = DateTime.Now.AddDays(session.ServerTableMetadata.ConstantsTable.BlackMarketSellEndDay).ToEpochSeconds(), + ExpiryTime = DateTime.Now.AddDays(Constants.BlackMarketSellEndDay).ToEpochSeconds(), Price = price, Quantity = quantity, }; diff --git a/Maple2.Server.Game/Manager/BuddyManager.cs b/Maple2.Server.Game/Manager/BuddyManager.cs index 707d7076e..cb03d11f5 100644 --- a/Maple2.Server.Game/Manager/BuddyManager.cs +++ b/Maple2.Server.Game/Manager/BuddyManager.cs @@ -17,6 +17,8 @@ namespace Maple2.Server.Game.Manager; public class BuddyManager : IDisposable { private readonly GameSession session; + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + private readonly IDictionary buddies; private readonly IDictionary blocked; @@ -87,7 +89,7 @@ public void SendInvite(string name, string message) { session.Send(BuddyPacket.Invite(error: s_buddy_err_my_id_ex)); return; } - if (buddies.Count >= session.ServerTableMetadata.ConstantsTable.MaxBuddyCount) { + if (buddies.Count >= Constants.MaxBuddyCount) { session.Send(BuddyPacket.Invite(error: s_buddy_err_max_buddy)); return; } @@ -113,7 +115,7 @@ public void SendInvite(string name, string message) { try { db.BeginTransaction(); - if (db.CountBuddy(receiverId) >= session.ServerTableMetadata.ConstantsTable.MaxBuddyCount) { + if (db.CountBuddy(receiverId) >= Constants.MaxBuddyCount) { session.Send(BuddyPacket.Invite(name: name, error: s_buddy_err_target_full)); return; } @@ -262,7 +264,7 @@ public void SendBlock(long entryId, string name, string message) { session.Send(BuddyPacket.Block(error: s_buddy_err_unknown)); return; } - if (blocked.Count >= session.ServerTableMetadata.ConstantsTable.MaxBlockCount) { + if (blocked.Count >= Constants.MaxBlockCount) { session.Send(BuddyPacket.Block(name: name, error: s_buddy_err_max_block)); return; } diff --git a/Maple2.Server.Game/Manager/ConfigManager.cs b/Maple2.Server.Game/Manager/ConfigManager.cs index bfe26ea37..0e15eb24a 100644 --- a/Maple2.Server.Game/Manager/ConfigManager.cs +++ b/Maple2.Server.Game/Manager/ConfigManager.cs @@ -18,6 +18,8 @@ public class ConfigManager { private readonly GameSession session; + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + private readonly IDictionary keyBinds; private short activeHotBar; private readonly List hotBars; @@ -97,12 +99,12 @@ public ConfigManager(GameStorage.Request db, GameSession session) { ExplorationProgress = load.ExplorationProgress; statLimits = new Dictionary() { - { "StatPointLimit_str", session.ServerTableMetadata.ConstantsTable.StatPointLimit_str }, - { "StatPointLimit_dex", session.ServerTableMetadata.ConstantsTable.StatPointLimit_dex }, - { "StatPointLimit_int", session.ServerTableMetadata.ConstantsTable.StatPointLimit_int }, - { "StatPointLimit_luk", session.ServerTableMetadata.ConstantsTable.StatPointLimit_luk }, - { "StatPointLimit_hp", session.ServerTableMetadata.ConstantsTable.StatPointLimit_hp }, - { "StatPointLimit_cap", session.ServerTableMetadata.ConstantsTable.StatPointLimit_cap } + { "StatPointLimit_str", Constants.StatPointLimit_str }, + { "StatPointLimit_dex", Constants.StatPointLimit_dex }, + { "StatPointLimit_int", Constants.StatPointLimit_int }, + { "StatPointLimit_luk", Constants.StatPointLimit_luk }, + { "StatPointLimit_hp", Constants.StatPointLimit_hp }, + { "StatPointLimit_cap", Constants.StatPointLimit_cap } }; statAttributes = new StatAttributes(statLimits); @@ -336,7 +338,7 @@ public void LoadRevival() { /// The tick when the penalty ends, or 0 to reset public void UpdateDeathPenalty(long endTick) { // Skip penalty for low level players - if (session.Player.Value.Character.Level < session.ServerTableMetadata.ConstantsTable.UserRevivalPaneltyMinLevel) { + if (session.Player.Value.Character.Level < Constants.UserRevivalPaneltyMinLevel) { return; } diff --git a/Maple2.Server.Game/Manager/CurrencyManager.cs b/Maple2.Server.Game/Manager/CurrencyManager.cs index f056a4229..e0465e0f5 100644 --- a/Maple2.Server.Game/Manager/CurrencyManager.cs +++ b/Maple2.Server.Game/Manager/CurrencyManager.cs @@ -9,6 +9,7 @@ namespace Maple2.Server.Game.Manager; public class CurrencyManager { private readonly GameSession session; + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; private Currency Currency => session.Player.Value.Currency; public CurrencyManager(GameSession session) { @@ -98,57 +99,57 @@ public long this[CurrencyType type] { long overflow; switch (type) { case CurrencyType.ValorToken: - delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.HonorTokenMax) - Currency.ValorToken; - overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.HonorTokenMax); - Currency.ValorToken = Math.Min(value, session.ServerTableMetadata.ConstantsTable.HonorTokenMax); + delta = Math.Min(value, Constants.HonorTokenMax) - Currency.ValorToken; + overflow = Math.Max(0, value - Constants.HonorTokenMax); + Currency.ValorToken = Math.Min(value, Constants.HonorTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_honor_token, delta); } break; case CurrencyType.Treva: - delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.KarmaTokenMax) - Currency.Treva; - overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.KarmaTokenMax); - Currency.Treva = Math.Min(value, session.ServerTableMetadata.ConstantsTable.KarmaTokenMax); + delta = Math.Min(value, Constants.KarmaTokenMax) - Currency.Treva; + overflow = Math.Max(0, value - Constants.KarmaTokenMax); + Currency.Treva = Math.Min(value, Constants.KarmaTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_karma_token, delta); } break; case CurrencyType.Rue: - delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.LuTokenMax) - Currency.Rue; - overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.LuTokenMax); - Currency.Rue = Math.Min(value, session.ServerTableMetadata.ConstantsTable.LuTokenMax); + delta = Math.Min(value, Constants.LuTokenMax) - Currency.Rue; + overflow = Math.Max(0, value - Constants.LuTokenMax); + Currency.Rue = Math.Min(value, Constants.LuTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_lu_token, delta); } break; case CurrencyType.HaviFruit: - delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.HabiTokenMax) - Currency.HaviFruit; - overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.HabiTokenMax); - Currency.HaviFruit = Math.Min(value, session.ServerTableMetadata.ConstantsTable.HabiTokenMax); + delta = Math.Min(value, Constants.HabiTokenMax) - Currency.HaviFruit; + overflow = Math.Max(0, value - Constants.HabiTokenMax); + Currency.HaviFruit = Math.Min(value, Constants.HabiTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_habi_token, delta); } break; case CurrencyType.ReverseCoin: - delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.ReverseCoinMax) - Currency.ReverseCoin; - overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.ReverseCoinMax); - Currency.ReverseCoin = Math.Min(value, session.ServerTableMetadata.ConstantsTable.ReverseCoinMax); + delta = Math.Min(value, Constants.ReverseCoinMax) - Currency.ReverseCoin; + overflow = Math.Max(0, value - Constants.ReverseCoinMax); + Currency.ReverseCoin = Math.Min(value, Constants.ReverseCoinMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_reverse_coin, delta); } break; case CurrencyType.MentorToken: - delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.MentorTokenMax) - Currency.MentorToken; - overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.MentorTokenMax); - Currency.MentorToken = Math.Min(value, session.ServerTableMetadata.ConstantsTable.MentorTokenMax); + delta = Math.Min(value, Constants.MentorTokenMax) - Currency.MentorToken; + overflow = Math.Max(0, value - Constants.MentorTokenMax); + Currency.MentorToken = Math.Min(value, Constants.MentorTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_mentor_token, delta); } break; case CurrencyType.MenteeToken: - delta = Math.Min(value, session.ServerTableMetadata.ConstantsTable.MenteeTokenMax) - Currency.MenteeToken; - overflow = Math.Max(0, value - session.ServerTableMetadata.ConstantsTable.MenteeTokenMax); - Currency.MenteeToken = Math.Min(value, session.ServerTableMetadata.ConstantsTable.MenteeTokenMax); + delta = Math.Min(value, Constants.MenteeTokenMax) - Currency.MenteeToken; + overflow = Math.Max(0, value - Constants.MenteeTokenMax); + Currency.MenteeToken = Math.Min(value, Constants.MenteeTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_mentee_token, delta); } diff --git a/Maple2.Server.Game/Manager/ExperienceManager.cs b/Maple2.Server.Game/Manager/ExperienceManager.cs index 52985f35a..fe8ed46ec 100644 --- a/Maple2.Server.Game/Manager/ExperienceManager.cs +++ b/Maple2.Server.Game/Manager/ExperienceManager.cs @@ -52,6 +52,8 @@ public long PrestigeCurrentExp { private int ChainKillCount { get; set; } + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + public ExperienceManager(GameSession session) { this.session = session; Init(); @@ -89,7 +91,7 @@ public void OnKill(IActor npc) { } private long GetRestExp(long expGained) { - long addedRestExp = Math.Min(RestExp, (long) (expGained * (session.ServerTableMetadata.ConstantsTable.RestExpAcquireRate / 10000.0f))); // convert int to a percentage + long addedRestExp = Math.Min(RestExp, (long) (expGained * (Constants.RestExpAcquireRate / 10000.0f))); // convert int to a percentage RestExp = Math.Max(0, RestExp - addedRestExp); Exp += expGained; return addedRestExp; @@ -175,7 +177,7 @@ public void AddMobExp(int moblevel, float modifier = 1f, long additionalExp = 0) public bool LevelUp() { int startLevel = Level; - for (int level = startLevel; level < session.ServerTableMetadata.ConstantsTable.characterMaxLevel; level++) { + for (int level = startLevel; level < Constants.characterMaxLevel; level++) { if (!session.TableMetadata.ExpTable.NextExp.TryGetValue(level, out long expToNextLevel) || expToNextLevel > Exp) { break; } @@ -203,7 +205,7 @@ public bool LevelUp() { } private void AddPrestigeExp(ExpType expType) { - if (Level < session.ServerTableMetadata.ConstantsTable.AdventureLevelStartLevel) { + if (Level < Constants.AdventureLevelStartLevel) { return; } @@ -211,20 +213,20 @@ private void AddPrestigeExp(ExpType expType) { return; } - if (PrestigeCurrentExp - PrestigeExp + (PrestigeLevelsGained * session.ServerTableMetadata.ConstantsTable.AdventureLevelLvUpExp) >= - session.ServerTableMetadata.ConstantsTable.AdventureLevelLvUpExp) { - amount = (long) (amount * session.ServerTableMetadata.ConstantsTable.AdventureLevelFactor); + if (PrestigeCurrentExp - PrestigeExp + (PrestigeLevelsGained * Constants.AdventureLevelLvUpExp) >= + Constants.AdventureLevelLvUpExp) { + amount = (long) (amount * Constants.AdventureLevelFactor); } PrestigeCurrentExp = Math.Min(amount + PrestigeCurrentExp, long.MaxValue); int startLevel = PrestigeLevel; - for (int level = startLevel; level < session.ServerTableMetadata.ConstantsTable.AdventureLevelLimit; level++) { - if (session.ServerTableMetadata.ConstantsTable.AdventureLevelLvUpExp > PrestigeCurrentExp) { + for (int level = startLevel; level < Constants.AdventureLevelLimit; level++) { + if (Constants.AdventureLevelLvUpExp > PrestigeCurrentExp) { break; } - PrestigeCurrentExp -= session.ServerTableMetadata.ConstantsTable.AdventureLevelLvUpExp; + PrestigeCurrentExp -= Constants.AdventureLevelLvUpExp; PrestigeLevel++; } session.Send(PrestigePacket.AddExp(PrestigeCurrentExp, amount)); @@ -234,7 +236,7 @@ private void AddPrestigeExp(ExpType expType) { } public void PrestigeLevelUp(int amount = 1) { - PrestigeLevel = Math.Clamp(PrestigeLevel + amount, amount, session.ServerTableMetadata.ConstantsTable.AdventureLevelLimit); + PrestigeLevel = Math.Clamp(PrestigeLevel + amount, amount, Constants.AdventureLevelLimit); PrestigeLevelsGained += amount; session.ConditionUpdate(ConditionType.adventure_level, counter: amount); session.ConditionUpdate(ConditionType.adventure_level_up, counter: amount); @@ -243,7 +245,7 @@ public void PrestigeLevelUp(int amount = 1) { } for (int i = 0; i < amount; i++) { - Item? item = session.Field?.ItemDrop.CreateItem(session.ServerTableMetadata.ConstantsTable.AdventureLevelLvUpRewardItem); + Item? item = session.Field?.ItemDrop.CreateItem(Constants.AdventureLevelLvUpRewardItem); if (item == null) { break; } diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs index 2897d2211..d078b2de7 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs @@ -143,8 +143,8 @@ public FieldPlayer SpawnPlayer(GameSession session, Player player, int portalId AnimationMetadata? animation = NpcMetadata.GetAnimation(npc.Model.Name); string aiPath = disableAi ? string.Empty : npc.AiPath; - var fieldNpc = new FieldNpc(this, NextLocalId(), agent, new Npc(npc, animation, ServerTableMetadata.ConstantsTable.NpcLastingSightRadius, - ServerTableMetadata.ConstantsTable.NpcLastingSightHeightUp, ServerTableMetadata.ConstantsTable.NpcLastingSightHeightDown), aiPath, + var fieldNpc = new FieldNpc(this, NextLocalId(), agent, new Npc(npc, animation, Constants.NpcLastingSightRadius, + Constants.NpcLastingSightHeightUp, Constants.NpcLastingSightHeightDown), aiPath, patrolDataUUID: spawnPointNpc?.PatrolData, spawnAnimation: spawnAnimation) { Owner = owner, Position = spawnPosition, @@ -183,8 +183,8 @@ public FieldPlayer SpawnPlayer(GameSession session, Player player, int portalId int objectId = player != null ? NextGlobalId() : NextLocalId(); AnimationMetadata? animation = NpcMetadata.GetAnimation(npc.Model.Name); - var fieldPet = new FieldPet(this, objectId, agent, new Npc(npc, animation, ServerTableMetadata.ConstantsTable.NpcLastingSightRadius, - ServerTableMetadata.ConstantsTable.NpcLastingSightHeightUp,ServerTableMetadata.ConstantsTable.NpcLastingSightHeightDown), + var fieldPet = new FieldPet(this, objectId, agent, new Npc(npc, animation, Constants.NpcLastingSightRadius, + Constants.NpcLastingSightHeightUp,Constants.NpcLastingSightHeightDown), pet, petMetadata, Constant.PetFieldAiPath, player) { Owner = owner, Position = position, @@ -219,16 +219,16 @@ public FieldPortal SpawnPortal(Portal portal, int roomId, Vector3 position = def public FieldPortal SpawnPortal(QuestSummonPortal metadata, FieldNpc npc, FieldPlayer owner) { var portal = new Portal(NextLocalId(), metadata.MapId, metadata.PortalId, PortalType.Quest, PortalActionType.Interact, - npc.Position.Offset(owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalDistanceFromNpc, npc.Rotation), npc.Rotation, - new Vector3(owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalDistanceFromNpc, owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalDimensionY, - owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalDimensionZ), owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalDistanceFromNpc, + npc.Position.Offset(Constants.QuestPortalDistanceFromNpc, npc.Rotation), npc.Rotation, + new Vector3(Constants.QuestPortalDistanceFromNpc, Constants.QuestPortalDimensionY, + Constants.QuestPortalDimensionZ), Constants.QuestPortalDistanceFromNpc, 0, true, false, true); var fieldPortal = new FieldQuestPortal(owner, this, NextLocalId(), portal) { Position = portal.Position, Rotation = portal.Rotation, - EndTick = (FieldTick + (long) TimeSpan.FromSeconds(owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalKeepTime).TotalMilliseconds).Truncate32(), + EndTick = (FieldTick + (long) TimeSpan.FromSeconds(Constants.QuestPortalKeepTime).TotalMilliseconds).Truncate32(), StartTick = FieldTickInt, - Model = owner.Session.ServerTableMetadata.ConstantsTable.QuestPortalKeepNif, + Model = Constants.QuestPortalKeepNif, }; fieldPortals[fieldPortal.ObjectId] = fieldPortal; @@ -725,7 +725,7 @@ public void RemoveSkillByTriggerId(int triggerId) { private void AddCubeSkill(SkillMetadata metadata, in Vector3 position, in Vector3 rotation = default) { Vector3 adjustedPosition = position; adjustedPosition.Z += FieldAccelerationStructure.BLOCK_SIZE; - var fieldSkill = new FieldSkill(this, NextLocalId(), FieldActor, metadata, (int)ServerTableMetadata.ConstantsTable.GlobalCubeSkillIntervalTime.TotalMilliseconds, adjustedPosition) { + var fieldSkill = new FieldSkill(this, NextLocalId(), FieldActor, metadata, (int)Constants.GlobalCubeSkillIntervalTime.TotalMilliseconds, adjustedPosition) { Position = adjustedPosition, Rotation = rotation, Source = SkillSource.Cube, diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs index 4baba0a13..cafe62325 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs @@ -71,6 +71,9 @@ public partial class FieldManager : IField { private readonly Thread thread; private readonly List<(FieldPacketHandler handler, GameSession session, ByteReader reader)> queuedPackets; private bool initialized; + + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public bool Disposed { get; private set; } private readonly ILogger logger = Log.Logger.ForContext(); @@ -364,7 +367,7 @@ public void EnsurePlayerPosition(FieldPlayer player) { return; } - player.FallDamage(player.Session.ServerTableMetadata.ConstantsTable.FallBoundingAddedDistance); + player.FallDamage(Constants.FallBoundingAddedDistance); player.MoveToPosition(player.LastGroundPosition.Align() + new Vector3(0, 0, 150f), default); } diff --git a/Maple2.Server.Game/Manager/FishingManager.cs b/Maple2.Server.Game/Manager/FishingManager.cs index 46be60b03..318f4b9f0 100644 --- a/Maple2.Server.Game/Manager/FishingManager.cs +++ b/Maple2.Server.Game/Manager/FishingManager.cs @@ -28,6 +28,8 @@ private FieldGuideObject? GuideObject { private FishingTile? selectedTile; private IDictionary tiles = new Dictionary(); + private ConstantsTable Constants => serverTableMetadata.ConstantsTable; + private readonly ILogger logger = Log.ForContext(); public FishingManager(GameSession session, TableMetadataStorage tableMetadata, ServerTableMetadataStorage serverTableMetadata) { @@ -239,12 +241,12 @@ public FishingError Start(Vector3 position) { selectedFish = fishes.Get(); - int fishingTick = session.ServerTableMetadata.ConstantsTable.fisherBoreDuration; + int fishingTick = Constants.fisherBoreDuration; bool hasAutoFish = session.Player.Buffs.HasBuff(BuffEventType.AutoFish); // Fishing Success if (Random.Shared.Next(0, 10000) < selectedFish.BaitProbability) { - if (!hasAutoFish && Random.Shared.Next(0, 10000) < session.ServerTableMetadata.ConstantsTable.fishFightingProp) { + if (!hasAutoFish && Random.Shared.Next(0, 10000) < Constants.fishFightingProp) { fishFightGame = true; } diff --git a/Maple2.Server.Game/Manager/ItemMergeManager.cs b/Maple2.Server.Game/Manager/ItemMergeManager.cs index b9c30de3e..2ed470dbe 100644 --- a/Maple2.Server.Game/Manager/ItemMergeManager.cs +++ b/Maple2.Server.Game/Manager/ItemMergeManager.cs @@ -19,6 +19,8 @@ public sealed class ItemMergeManager { private Item? upgradeItem; private Item? catalystItem; + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + public ItemMergeManager(GameSession session) { this.session = session; } @@ -86,7 +88,7 @@ public void SelectCrystal(long itemUid, long crystalUid) { session.Send(ItemMergePacket.Select(mergeSlot, ItemMerge.CostMultiplier(upgradeItem.Rarity))); if (!session.ScriptMetadata.TryGet(Constant.EmpowermentNpc, out ScriptMetadata? script) || - !script.States.TryGetValue(session.ServerTableMetadata.ConstantsTable.MergeSmithScriptID, out ScriptState? state)) { + !script.States.TryGetValue(Constants.MergeSmithScriptID, out ScriptState? state)) { return; } diff --git a/Maple2.Server.Game/Manager/Items/InventoryManager.cs b/Maple2.Server.Game/Manager/Items/InventoryManager.cs index f9ce9fcf6..dedecfeb1 100644 --- a/Maple2.Server.Game/Manager/Items/InventoryManager.cs +++ b/Maple2.Server.Game/Manager/Items/InventoryManager.cs @@ -25,6 +25,8 @@ public class InventoryManager { private readonly ILogger logger = Log.Logger.ForContext(); + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + public InventoryManager(GameStorage.Request db, GameSession session) { this.session = session; tabs = new Dictionary(); @@ -46,42 +48,42 @@ public InventoryManager(GameStorage.Request db, GameSession session) { private short BaseSize(InventoryType type) { return type switch { - InventoryType.Gear => session.ServerTableMetadata.ConstantsTable.bagSlotTabGameCount[0], - InventoryType.Outfit => session.ServerTableMetadata.ConstantsTable.bagSlotTabSkinCount[0], - InventoryType.Mount => session.ServerTableMetadata.ConstantsTable.bagSlotTabSummonCount[0], - InventoryType.Catalyst => session.ServerTableMetadata.ConstantsTable.bagSlotTabMaterialCount[0], - InventoryType.FishingMusic => session.ServerTableMetadata.ConstantsTable.bagSlotTabLifeCount[0], - InventoryType.Quest => session.ServerTableMetadata.ConstantsTable.bagSlotTabQuestCount[0], - InventoryType.Gemstone => session.ServerTableMetadata.ConstantsTable.bagSlotTabGemCount[0], - InventoryType.Misc => session.ServerTableMetadata.ConstantsTable.bagSlotTabMiscCount[0], - InventoryType.LifeSkill => session.ServerTableMetadata.ConstantsTable.bagSlotTabMasteryCount[0], - InventoryType.Pets => session.ServerTableMetadata.ConstantsTable.bagSlotTabPetCount[0], - InventoryType.Consumable => session.ServerTableMetadata.ConstantsTable.bagSlotTabActiveSkillCount[0], - InventoryType.Currency => session.ServerTableMetadata.ConstantsTable.bagSlotTabCoinCount[0], - InventoryType.Badge => session.ServerTableMetadata.ConstantsTable.bagSlotTabBadgeCount[0], - InventoryType.Lapenshard => session.ServerTableMetadata.ConstantsTable.bagSlotTabLapenShardCount[0], - InventoryType.Fragment => session.ServerTableMetadata.ConstantsTable.bagSlotTabPieceCount[0], + InventoryType.Gear => Constants.bagSlotTabGameCount[0], + InventoryType.Outfit => Constants.bagSlotTabSkinCount[0], + InventoryType.Mount => Constants.bagSlotTabSummonCount[0], + InventoryType.Catalyst => Constants.bagSlotTabMaterialCount[0], + InventoryType.FishingMusic => Constants.bagSlotTabLifeCount[0], + InventoryType.Quest => Constants.bagSlotTabQuestCount[0], + InventoryType.Gemstone => Constants.bagSlotTabGemCount[0], + InventoryType.Misc => Constants.bagSlotTabMiscCount[0], + InventoryType.LifeSkill => Constants.bagSlotTabMasteryCount[0], + InventoryType.Pets => Constants.bagSlotTabPetCount[0], + InventoryType.Consumable => Constants.bagSlotTabActiveSkillCount[0], + InventoryType.Currency => Constants.bagSlotTabCoinCount[0], + InventoryType.Badge => Constants.bagSlotTabBadgeCount[0], + InventoryType.Lapenshard => Constants.bagSlotTabLapenShardCount[0], + InventoryType.Fragment => Constants.bagSlotTabPieceCount[0], _ => throw new ArgumentOutOfRangeException($"Invalid InventoryType: {type}"), }; } private short MaxExpandSize(InventoryType type) { return type switch { - InventoryType.Gear => session.ServerTableMetadata.ConstantsTable.bagSlotTabGameCount[1], - InventoryType.Outfit => session.ServerTableMetadata.ConstantsTable.bagSlotTabSkinCount[1], - InventoryType.Mount => session.ServerTableMetadata.ConstantsTable.bagSlotTabSummonCount[1], - InventoryType.Catalyst => session.ServerTableMetadata.ConstantsTable.bagSlotTabMaterialCount[1], - InventoryType.FishingMusic => session.ServerTableMetadata.ConstantsTable.bagSlotTabLifeCount[1], - InventoryType.Quest => session.ServerTableMetadata.ConstantsTable.bagSlotTabQuestCount[1], - InventoryType.Gemstone => session.ServerTableMetadata.ConstantsTable.bagSlotTabGemCount[1], - InventoryType.Misc => session.ServerTableMetadata.ConstantsTable.bagSlotTabMiscCount[1], - InventoryType.LifeSkill => session.ServerTableMetadata.ConstantsTable.bagSlotTabMasteryCount[1], - InventoryType.Pets => session.ServerTableMetadata.ConstantsTable.bagSlotTabPetCount[1], - InventoryType.Consumable => session.ServerTableMetadata.ConstantsTable.bagSlotTabActiveSkillCount[1], - InventoryType.Currency => session.ServerTableMetadata.ConstantsTable.bagSlotTabCoinCount[1], - InventoryType.Badge => session.ServerTableMetadata.ConstantsTable.bagSlotTabBadgeCount[1], - InventoryType.Lapenshard => session.ServerTableMetadata.ConstantsTable.bagSlotTabLapenShardCount[1], - InventoryType.Fragment => session.ServerTableMetadata.ConstantsTable.bagSlotTabPieceCount[1], + InventoryType.Gear => Constants.bagSlotTabGameCount[1], + InventoryType.Outfit => Constants.bagSlotTabSkinCount[1], + InventoryType.Mount => Constants.bagSlotTabSummonCount[1], + InventoryType.Catalyst => Constants.bagSlotTabMaterialCount[1], + InventoryType.FishingMusic => Constants.bagSlotTabLifeCount[1], + InventoryType.Quest => Constants.bagSlotTabQuestCount[1], + InventoryType.Gemstone => Constants.bagSlotTabGemCount[1], + InventoryType.Misc => Constants.bagSlotTabMiscCount[1], + InventoryType.LifeSkill => Constants.bagSlotTabMasteryCount[1], + InventoryType.Pets => Constants.bagSlotTabPetCount[1], + InventoryType.Consumable => Constants.bagSlotTabActiveSkillCount[1], + InventoryType.Currency => Constants.bagSlotTabCoinCount[1], + InventoryType.Badge => Constants.bagSlotTabBadgeCount[1], + InventoryType.Lapenshard => Constants.bagSlotTabLapenShardCount[1], + InventoryType.Fragment => Constants.bagSlotTabPieceCount[1], _ => throw new ArgumentOutOfRangeException($"Invalid InventoryType: {type}"), }; } @@ -557,7 +559,7 @@ public bool Expand(InventoryType type, int expandRowCount = Constant.InventoryEx return false; } - if (session.Currency.Meret < session.ServerTableMetadata.ConstantsTable.InventoryExpandPrice1Row) { + if (session.Currency.Meret < Constants.InventoryExpandPrice1Row) { session.Send(ItemInventoryPacket.Error(s_cannot_charge_merat)); return false; } @@ -566,7 +568,7 @@ public bool Expand(InventoryType type, int expandRowCount = Constant.InventoryEx return false; } - session.Currency.Meret -= session.ServerTableMetadata.ConstantsTable.InventoryExpandPrice1Row; + session.Currency.Meret -= Constants.InventoryExpandPrice1Row; if (session.Player.Value.Unlock.Expand.ContainsKey(type)) { session.Player.Value.Unlock.Expand[type] = newExpand; } else { diff --git a/Maple2.Server.Game/Manager/Items/StorageManager.cs b/Maple2.Server.Game/Manager/Items/StorageManager.cs index c38cd9a27..ac1487ac1 100644 --- a/Maple2.Server.Game/Manager/Items/StorageManager.cs +++ b/Maple2.Server.Game/Manager/Items/StorageManager.cs @@ -19,6 +19,7 @@ public sealed class StorageManager : IDisposable { private long mesos; private short expand; + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; public StorageManager(GameSession session) { this.session = session; @@ -189,11 +190,11 @@ public void WithdrawMesos(long amount) { public void Expand() { lock (session.Item) { short newSize = (short) (items.Size + Constant.InventoryExpandRowCount); - if (newSize > session.ServerTableMetadata.ConstantsTable.StoreExpandMaxSlotCount) { + if (newSize > Constants.StoreExpandMaxSlotCount) { session.Send(StorageInventoryPacket.Error(s_store_err_expand_max)); return; } - if (session.Currency.Meret < session.ServerTableMetadata.ConstantsTable.StoreExpandPrice1Row) { + if (session.Currency.Meret < Constants.StoreExpandPrice1Row) { session.Send(StorageInventoryPacket.Error(s_cannot_charge_merat)); return; } @@ -203,7 +204,7 @@ public void Expand() { return; } - session.Currency.Meret -= session.ServerTableMetadata.ConstantsTable.StoreExpandPrice1Row; + session.Currency.Meret -= Constants.StoreExpandPrice1Row; expand += Constant.InventoryExpandRowCount; Load(); diff --git a/Maple2.Server.Game/Manager/SkillManager.cs b/Maple2.Server.Game/Manager/SkillManager.cs index 19a38c285..7adcd762b 100644 --- a/Maple2.Server.Game/Manager/SkillManager.cs +++ b/Maple2.Server.Game/Manager/SkillManager.cs @@ -17,6 +17,8 @@ public class SkillManager { private readonly ILogger logger = Log.ForContext(); + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + public SkillManager(GameSession session, SkillBook skillBook) { this.session = session; @@ -121,11 +123,11 @@ public bool ExpandSkillTabs() { if (SkillBook.MaxSkillTabs >= Constant.MaxSkillTabCount) { return false; } - if (session.Currency.Meret < session.ServerTableMetadata.ConstantsTable.SkillBookTreeAddTabFeeMerat) { + if (session.Currency.Meret < Constants.SkillBookTreeAddTabFeeMerat) { return false; } - session.Currency.Meret -= session.ServerTableMetadata.ConstantsTable.SkillBookTreeAddTabFeeMerat; + session.Currency.Meret -= Constants.SkillBookTreeAddTabFeeMerat; SkillBook.MaxSkillTabs++; session.Send(SkillBookPacket.Expand(SkillBook)); diff --git a/Maple2.Server.Game/Manager/TradeManager.cs b/Maple2.Server.Game/Manager/TradeManager.cs index 67fd0f1d9..7e96e8707 100644 --- a/Maple2.Server.Game/Manager/TradeManager.cs +++ b/Maple2.Server.Game/Manager/TradeManager.cs @@ -23,6 +23,8 @@ private enum TradeState { private readonly object mutex = new(); + private ConstantsTable Constants => sender.Session.ServerTableMetadata.ConstantsTable; + public TradeManager(GameSession sender, GameSession receiver) { this.sender = new Trader(sender); this.receiver = new Trader(receiver); @@ -34,7 +36,7 @@ public TradeManager(GameSession sender, GameSession receiver) { // End the trade if not accepted before |TradeRequestDuration|. string receiverName = receiver.Player.Value.Character.Name; Task.Factory.StartNew(() => { - Thread.Sleep(TimeSpan.FromSeconds(sender.ServerTableMetadata.ConstantsTable.TradeRequestDuration)); + Thread.Sleep(TimeSpan.FromSeconds(Constants.TradeRequestDuration)); lock (mutex) { if (state is not (TradeState.Requested or TradeState.Acknowledged)) { return; @@ -168,7 +170,7 @@ public void SetMesos(GameSession caller, long amount) { return; } - if (amount > caller.ServerTableMetadata.ConstantsTable.TradeMaxMeso) { + if (amount > Constants.TradeMaxMeso) { caller.Send(TradePacket.Error(s_trade_error_invalid_meso)); return; } @@ -247,7 +249,7 @@ private void EndTrade(bool success) { } lock (sender.Session.Item) { - long fee = success ? (long) (sender.Session.ServerTableMetadata.ConstantsTable.TradeFeePercent / 100f * sender.Mesos) : 0; + long fee = success ? (long) (Constants.TradeFeePercent / 100f * sender.Mesos) : 0; sender.Session.Currency.Meso += sender.Mesos - fee; foreach (Item item in sender.Items) { if (item.Transfer?.Flag.HasFlag(TransferFlag.LimitTrade) == true) { @@ -260,7 +262,7 @@ private void EndTrade(bool success) { sender.Clear(); } lock (receiver.Session.Item) { - long fee = success ? (long) (receiver.Session.ServerTableMetadata.ConstantsTable.TradeFeePercent / 100f * receiver.Mesos) : 0; + long fee = success ? (long) (Constants.TradeFeePercent / 100f * receiver.Mesos) : 0; receiver.Session.Currency.Meso += receiver.Mesos - fee; foreach (Item item in receiver.Items) { if (item.Transfer?.Flag.HasFlag(TransferFlag.LimitTrade) == true) { diff --git a/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs b/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs index 7ef651123..1808184d5 100644 --- a/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs +++ b/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs @@ -10,6 +10,9 @@ public class NpcCleanupPatrolDataTask : NpcTask { private readonly MovementState movement; private readonly FieldPlayer player; private readonly Vector3? lastPosition; + + private ConstantsTable Constants => player.Session.ServerTableMetadata.ConstantsTable; + public override bool CancelOnInterrupt => false; public NpcCleanupPatrolDataTask(FieldPlayer player, TaskState taskState, MovementState movement) : base(taskState, NpcTaskPriority.Cleanup) { @@ -33,8 +36,8 @@ protected override void TaskResumed() { return; } - float maxDistance = player.Session.ServerTableMetadata.ConstantsTable.TalkableDistance * - player.Session.ServerTableMetadata.ConstantsTable.TalkableDistance; + float maxDistance = Constants.TalkableDistance * + Constants.TalkableDistance; // find nearest npc FieldNpc? closestNpc = player.Field.Npcs.Values diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs b/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs index accb7b90e..7fc577060 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs @@ -24,6 +24,8 @@ public sealed class FieldPet : FieldNpc { public int TamingPoint; private long tamingTick; + private ConstantsTable Constants => Field.ServerTableMetadata.ConstantsTable; + public FieldPet(FieldManager field, int objectId, DtCrowdAgent agent, Npc npc, Item pet, PetMetadata petMetadata, string aiPath, FieldPlayer? owner = null) : base(field, objectId, agent, npc, aiPath) { this.owner = owner; Pet = pet; @@ -64,7 +66,7 @@ public override void ApplyDamage(IActor caster, DamageRecord damage, SkillMetada } var targetRecord = new DamageRecordTarget(this); - int damageAmount = TamingPoint - Math.Min(TamingPoint + attack.Pet.TamingPoint, Field.ServerTableMetadata.ConstantsTable.TamingPetMaxPoint); + int damageAmount = TamingPoint - Math.Min(TamingPoint + attack.Pet.TamingPoint, Constants.TamingPetMaxPoint); TamingPoint -= damageAmount; targetRecord.AddDamage(damageAmount == 0 ? DamageType.Miss : DamageType.Normal, damageAmount); @@ -73,7 +75,7 @@ public override void ApplyDamage(IActor caster, DamageRecord damage, SkillMetada IsDead = true; OnDeath(); DropItem(caster); - } else if (TamingPoint >= Field.ServerTableMetadata.ConstantsTable.TamingPetMaxPoint) { // trap has chance to fail + } else if (TamingPoint >= Constants.TamingPetMaxPoint) { // trap has chance to fail IsDead = true; OnDeath(); DropItem(caster); diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs b/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs index 4179e9aaf..3a6abb4d7 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs @@ -98,6 +98,8 @@ public AdminPermissions AdminPermissions { private readonly EventQueue scheduler; + private ConstantsTable Constants => Session.ServerTableMetadata.ConstantsTable; + public FieldPlayer(GameSession session, Player player) : base(session.Field!, player.ObjectId, player, session.NpcMetadata) { Session = session; Animation = Session.Animation; @@ -168,7 +170,7 @@ public override void Update(long tickCount) { return; } - if (InBattle && tickCount - battleTick > Session.ServerTableMetadata.ConstantsTable.UserBattleDurationTick) { + if (InBattle && tickCount - battleTick > Constants.UserBattleDurationTick) { InBattle = false; } @@ -402,7 +404,7 @@ public bool Revive(bool instant = false) { // Apply death penalty if field requires it if (Field.Metadata.Property.DeathPenalty) { - Session.Config.UpdateDeathPenalty(Field.FieldTick + Session.ServerTableMetadata.ConstantsTable.UserRevivalPaneltyTick); + Session.Config.UpdateDeathPenalty(Field.FieldTick + Constants.UserRevivalPaneltyTick); } // Update revival condition @@ -474,7 +476,7 @@ public void ConsumeHp(int amount) { Stat stat = Stats.Values[BasicAttribute.Health]; stat.Add(-amount); if (!IsDead) { - lastRegenTime[BasicAttribute.Health] = Field.FieldTick + Session.ServerTableMetadata.ConstantsTable.RecoveryHPWaitTick; + lastRegenTime[BasicAttribute.Health] = Field.FieldTick + Constants.RecoveryHPWaitTick; } Session.Send(StatsPacket.Update(this, BasicAttribute.Health)); @@ -547,7 +549,7 @@ public void ConsumeStamina(int amount, bool noRegen = false) { Stats.Values[BasicAttribute.Stamina].Add(-amount); if (!IsDead) { - lastRegenTime[BasicAttribute.Stamina] = Field.FieldTick + Session.ServerTableMetadata.ConstantsTable.RecoveryEPWaitTick; + lastRegenTime[BasicAttribute.Stamina] = Field.FieldTick + Constants.RecoveryEPWaitTick; } Field.Broadcast(StatsPacket.Update(this, BasicAttribute.Stamina)); } diff --git a/Maple2.Server.Game/Model/Field/Tombstone.cs b/Maple2.Server.Game/Model/Field/Tombstone.cs index 0d0b7a488..02debf679 100644 --- a/Maple2.Server.Game/Model/Field/Tombstone.cs +++ b/Maple2.Server.Game/Model/Field/Tombstone.cs @@ -24,10 +24,12 @@ public byte HitsRemaining { public int Unknown1 { get; } = 1; public bool Unknown2 { get; } + private ConstantsTable Constants => Owner.Session.ServerTableMetadata.ConstantsTable; + public Tombstone(FieldPlayer owner, int totalDeaths) { Owner = owner; - TotalHitCount = (byte) Math.Min(totalDeaths * owner.Session.ServerTableMetadata.ConstantsTable.hitPerDeadCount, - owner.Session.ServerTableMetadata.ConstantsTable.hitPerDeadCount * owner.Session.ServerTableMetadata.ConstantsTable.maxDeadCount); + TotalHitCount = (byte) Math.Min(totalDeaths * Constants.hitPerDeadCount, + Constants.hitPerDeadCount * Constants.maxDeadCount); hitsRemaining = TotalHitCount; } public void WriteTo(IByteWriter writer) { diff --git a/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs b/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs index 99cfb24c7..f31755a71 100644 --- a/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs @@ -25,10 +25,13 @@ public class BeautyHandler : FieldPacketHandler { // ReSharper disable MemberCanBePrivate.Global public required ItemMetadataStorage ItemMetadata { private get; init; } public required TableMetadataStorage TableMetadata { private get; init; } - + public required NpcMetadataStorage NpcMetadata { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } // ReSharper restore All #endregion + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + private enum Command : byte { Shop = 0, CreateBeauty = 3, @@ -47,12 +50,6 @@ private enum Command : byte { Voucher = 23, } - #region Autofac Autowired - // ReSharper disable MemberCanBePrivate.Global - public required NpcMetadataStorage NpcMetadata { private get; init; } - // ReSharper restore All - #endregion - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -351,15 +348,15 @@ private void HandleRandomHair(GameSession session, IByteReader packet) { private void HandleWarp(GameSession session, IByteReader packet) { short type = packet.ReadShort(); int mapId = type switch { - 1 => session.ServerTableMetadata.ConstantsTable.BeautyHairShopGotoFieldID, - 3 => session.ServerTableMetadata.ConstantsTable.BeautyFaceShopGotoFieldID, - 5 => session.ServerTableMetadata.ConstantsTable.BeautyColorShopGotoFieldID, + 1 => Constants.BeautyHairShopGotoFieldID, + 3 => Constants.BeautyFaceShopGotoFieldID, + 5 => Constants.BeautyColorShopGotoFieldID, _ => 0, }; int portalId = type switch { - 1 => session.ServerTableMetadata.ConstantsTable.BeautyHairShopGotoPortalID, - 3 => session.ServerTableMetadata.ConstantsTable.BeautyFaceShopGotoPortalID, - 5 => session.ServerTableMetadata.ConstantsTable.BeautyColorShopGotoPortalID, + 1 => Constants.BeautyHairShopGotoPortalID, + 3 => Constants.BeautyFaceShopGotoPortalID, + 5 => Constants.BeautyColorShopGotoPortalID, _ => 0, }; diff --git a/Maple2.Server.Game/PacketHandlers/ClubHandler.cs b/Maple2.Server.Game/PacketHandlers/ClubHandler.cs index 293589ef0..da01d5b69 100644 --- a/Maple2.Server.Game/PacketHandlers/ClubHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/ClubHandler.cs @@ -34,9 +34,12 @@ private enum Command : byte { // ReSharper disable MemberCanBePrivate.Global public required WorldClient World { private get; init; } public required BanWordStorage BanWordStorage { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } // ReSharper restore All #endregion + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -71,7 +74,7 @@ private void HandleCreate(GameSession session, IByteReader packet) { session.Send(ClubPacket.Error(ClubError.s_club_err_name_value)); return; } - if (clubName.Length < session.ServerTableMetadata.ConstantsTable.ClubNameLengthMin || clubName.Length > session.ServerTableMetadata.ConstantsTable.ClubNameLengthMax) { + if (clubName.Length < Constants.ClubNameLengthMin || clubName.Length > Constants.ClubNameLengthMax) { session.Send(ClubPacket.Error(ClubError.s_club_err_name_value)); return; } @@ -243,7 +246,7 @@ private void HandleRename(GameSession session, IByteReader packet) { session.Send(ClubPacket.Error(ClubError.s_club_err_name_value)); return; } - if (newName.Length < session.ServerTableMetadata.ConstantsTable.ClubNameLengthMin || newName.Length > session.ServerTableMetadata.ConstantsTable.ClubNameLengthMax) { + if (newName.Length < Constants.ClubNameLengthMin || newName.Length > Constants.ClubNameLengthMax) { session.Send(ClubPacket.Error(ClubError.s_club_err_name_value)); return; } diff --git a/Maple2.Server.Game/PacketHandlers/GuildHandler.cs b/Maple2.Server.Game/PacketHandlers/GuildHandler.cs index 8b4e124fd..57714794f 100644 --- a/Maple2.Server.Game/PacketHandlers/GuildHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/GuildHandler.cs @@ -65,10 +65,13 @@ private enum Command : byte { public required WorldClient World { private get; init; } public required TableMetadataStorage TableMetadata { private get; init; } public required BanWordStorage BanWordStorage { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } // ReSharper restore All #endregion + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -193,7 +196,7 @@ private void HandleCreate(GameSession session, IByteReader packet) { session.Send(GuildPacket.Error(GuildError.s_guild_err_name_value)); return; } - if (guildName.Length < session.ServerTableMetadata.ConstantsTable.GuildNameLengthMin || guildName.Length > session.ServerTableMetadata.ConstantsTable.GuildNameLengthMax) { + if (guildName.Length < Constants.GuildNameLengthMin || guildName.Length > Constants.GuildNameLengthMax) { session.Send(GuildPacket.Error(GuildError.s_guild_err_name_value)); return; } @@ -208,11 +211,11 @@ private void HandleCreate(GameSession session, IByteReader packet) { return; } - if (session.Player.Value.Character.Level < session.ServerTableMetadata.ConstantsTable.GuildCreateMinLevel) { + if (session.Player.Value.Character.Level < Constants.GuildCreateMinLevel) { session.Send(GuildPacket.Error(GuildError.s_guild_err_not_enough_level)); return; } - if (session.Currency.CanAddMeso(-session.ServerTableMetadata.ConstantsTable.GuildCreatePrice) != -session.ServerTableMetadata.ConstantsTable.GuildCreatePrice) { + if (session.Currency.CanAddMeso(-Constants.GuildCreatePrice) != -Constants.GuildCreatePrice) { session.Send(GuildPacket.Error(GuildError.s_guild_err_no_money)); return; } @@ -236,7 +239,7 @@ private void HandleCreate(GameSession session, IByteReader packet) { } session.Guild.SetGuild(response.Guild); - session.Currency.Meso -= session.ServerTableMetadata.ConstantsTable.GuildCreatePrice; + session.Currency.Meso -= Constants.GuildCreatePrice; session.Guild.Load(); session.Send(GuildPacket.Created(guildName)); diff --git a/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs b/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs index 5026761ba..67166ee36 100644 --- a/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs @@ -1,9 +1,11 @@ -using Maple2.Model.Metadata; +using Maple2.Database.Storage; +using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Server.Core.Constants; -using Maple2.Server.Game.PacketHandlers.Field; using Maple2.Server.Core.Packets; +using Maple2.Server.Game.PacketHandlers.Field; using Maple2.Server.Game.Session; +using static Maple2.Server.World.Service.World; namespace Maple2.Server.Game.PacketHandlers; @@ -15,12 +17,21 @@ private enum Command : byte { Premium = 2, } + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + + // ReSharper restore All + #endregion + + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { case Command.Home: long time = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - if (session.Player.Value.Character.StorageCooldown + session.ServerTableMetadata.ConstantsTable.HomeBankCallCooltime > time) { + if (session.Player.Value.Character.StorageCooldown + Constants.HomeBankCallCooltime > time) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs b/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs index b306b9867..29bcbce1d 100644 --- a/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs @@ -1,10 +1,11 @@ -using Maple2.Model.Enum; +using Maple2.Database.Storage; +using Maple2.Model.Enum; using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Server.Core.Constants; -using Maple2.Server.Game.PacketHandlers.Field; using Maple2.Server.Core.Packets; using Maple2.Server.Game.LuaFunctions; +using Maple2.Server.Game.PacketHandlers.Field; using Maple2.Server.Game.Session; namespace Maple2.Server.Game.PacketHandlers; @@ -12,10 +13,19 @@ namespace Maple2.Server.Game.PacketHandlers; public class HomeDoctorHandler : FieldPacketHandler { public override RecvOp OpCode => RecvOp.RequestHomeDoctor; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + + // ReSharper restore All + #endregion + + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { if (session.Field is null) return; long time = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - if (session.Player.Value.Character.DoctorCooldown + session.ServerTableMetadata.ConstantsTable.HomeDoctorCallCooltime > time) { + if (session.Player.Value.Character.DoctorCooldown + Constants.HomeDoctorCallCooltime > time) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs b/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs index ac45bf140..69ed4263c 100644 --- a/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs @@ -1,4 +1,5 @@ -using Maple2.Model.Game; +using Maple2.Database.Storage; +using Maple2.Model.Game; using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Server.Core.Constants; @@ -18,6 +19,15 @@ private enum Command : byte { Commit = 3, } + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + + // ReSharper restore All + #endregion + + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -31,7 +41,7 @@ public override void Handle(GameSession session, IByteReader packet) { HandleUnstage(session, packet); return; case Command.Commit: - HandleCommit(session, packet); + HandleCommit(session, packet, Constants); return; } } @@ -69,7 +79,7 @@ private static void HandleUnstage(GameSession session, IByteReader packet) { } } - private static void HandleCommit(GameSession session, IByteReader packet) { + private static void HandleCommit(GameSession session, IByteReader packet, ConstantsTable constants) { bool unlock = packet.ReadBool(); // false - lock|true - unlock lock (session.Item) { @@ -86,7 +96,7 @@ private static void HandleCommit(GameSession session, IByteReader packet) { if (unlock && item.IsLocked) { item.IsLocked = false; - item.UnlockTime = DateTimeOffset.UtcNow.AddSeconds(session.ServerTableMetadata.ConstantsTable.ItemUnLockTime).ToUnixTimeSeconds(); + item.UnlockTime = DateTimeOffset.UtcNow.AddSeconds(constants.ItemUnLockTime).ToUnixTimeSeconds(); updatedItems.Add(item); } else if (!unlock && !item.IsLocked) { item.IsLocked = true; diff --git a/Maple2.Server.Game/PacketHandlers/JobHandler.cs b/Maple2.Server.Game/PacketHandlers/JobHandler.cs index 0e0b720bd..9464d381b 100644 --- a/Maple2.Server.Game/PacketHandlers/JobHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/JobHandler.cs @@ -1,10 +1,12 @@ -using Maple2.Model; +using Maple2.Database.Storage; +using Maple2.Model; using Maple2.Model.Enum; using Maple2.Model.Game; +using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Server.Core.Constants; -using Maple2.Server.Game.PacketHandlers.Field; using Maple2.Server.Game.Model; +using Maple2.Server.Game.PacketHandlers.Field; using Maple2.Server.Game.Packets; using Maple2.Server.Game.Session; @@ -22,6 +24,15 @@ private enum Command : byte { AutoDistribute = 11, } + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + + // ReSharper restore All + #endregion + + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -93,7 +104,7 @@ private void HandleAdvance(GameSession session, IByteReader packet) { session.Player.Buffs.Clear(); session.Player.Buffs.Initialize(); - session.Player.Buffs.LoadFieldBuffs(session.ServerTableMetadata.ConstantsTable.shadowWorldBuffHpUp, session.ServerTableMetadata.ConstantsTable.shadowWorldBuffMoveProtect); + session.Player.Buffs.LoadFieldBuffs(Constants.shadowWorldBuffHpUp, Constants.shadowWorldBuffMoveProtect); session.Stats.Refresh(); session.Field.Broadcast(JobPacket.Advance(session.Player, session.Config.Skill.SkillInfo)); session.ConditionUpdate(ConditionType.job, codeLong: (int) session.NpcScript.JobCondition.ChangeToJobCode); diff --git a/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs b/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs index 2bb305f3e..72d0cb80c 100644 --- a/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs @@ -21,9 +21,12 @@ public class MeretMarketHandler : FieldPacketHandler { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required TableMetadataStorage TableMetadata { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } // ReSharper restore All #endregion + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + private enum Command : byte { LoadPersonalListings = 11, LoadSales = 12, @@ -151,10 +154,10 @@ private void HandleListItem(GameSession session, IByteReader packet) { Look = item.Template, Blueprint = item.Blueprint ?? new ItemBlueprint(), Status = UgcMarketListingStatus.Active, - PromotionEndTime = promote ? DateTime.Now.AddHours(session.ServerTableMetadata.ConstantsTable.UGCShopAdHour).ToEpochSeconds() : 0, - ListingEndTime = DateTime.Now.AddDays(session.ServerTableMetadata.ConstantsTable.UGCShopSaleDay).ToEpochSeconds(), + PromotionEndTime = promote ? DateTime.Now.AddHours(Constants.UGCShopAdHour).ToEpochSeconds() : 0, + ListingEndTime = DateTime.Now.AddDays(Constants.UGCShopSaleDay).ToEpochSeconds(), CreationTime = DateTime.Now.ToEpochSeconds(), - Price = Math.Clamp(price, session.ServerTableMetadata.ConstantsTable.UGCShopSellMinPrice, session.ServerTableMetadata.ConstantsTable.UGCShopSellMaxPrice), + Price = Math.Clamp(price, Constants.UGCShopSellMinPrice, Constants.UGCShopSellMaxPrice), TabId = tabId, }; @@ -198,8 +201,8 @@ private void HandleRelistItem(GameSession session, IByteReader packet) { } item.Price = price; - item.PromotionEndTime = promote ? DateTime.Now.AddHours(session.ServerTableMetadata.ConstantsTable.UGCShopAdHour).ToEpochSeconds() : 0; - item.ListingEndTime = DateTime.Now.AddDays(session.ServerTableMetadata.ConstantsTable.UGCShopSaleDay).ToEpochSeconds(); + item.PromotionEndTime = promote ? DateTime.Now.AddHours(Constants.UGCShopAdHour).ToEpochSeconds() : 0; + item.ListingEndTime = DateTime.Now.AddDays(Constants.UGCShopSaleDay).ToEpochSeconds(); item.Status = UgcMarketListingStatus.Active; item.Description = description; item.Tags = tags; diff --git a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs index cf3ccffd2..817e22a4b 100644 --- a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs @@ -25,14 +25,22 @@ private enum Command : byte { Purchase = 8, } + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + // ReSharper restore All + #endregion + + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { case Command.Load: - HandleLoad(session); + HandleLoad(session, Constants); return; case Command.Create: - HandleCreate(session, packet); + HandleCreate(session, packet, Constants); return; case Command.Cancel: HandleCancel(session, packet); @@ -46,7 +54,7 @@ public override void Handle(GameSession session, IByteReader packet) { } } - private static void HandleLoad(GameSession session) { + private static void HandleLoad(GameSession session, ConstantsTable constants) { session.Send(MesoMarketPacket.Load(AVERAGE_PRICE)); session.Send(MesoMarketPacket.Quota(session.Player.Value.Account.MesoMarketListed, session.Player.Value.Account.MesoMarketPurchased)); @@ -55,11 +63,11 @@ private static void HandleLoad(GameSession session) { session.Send(MesoMarketPacket.MyListings(myListings)); } - private static void HandleCreate(GameSession session, IByteReader packet) { + private static void HandleCreate(GameSession session, IByteReader packet, ConstantsTable constants) { long amount = packet.ReadLong(); long price = packet.ReadLong(); - if (amount != session.ServerTableMetadata.ConstantsTable.MesoMarketBasePrice) { + if (amount != constants.MesoMarketBasePrice) { session.Send(MesoMarketPacket.Error(s_mesoMarket_error_invalidSaleMoney)); return; } @@ -96,7 +104,7 @@ private static void HandleCreate(GameSession session, IByteReader packet) { } session.Player.Value.Account.MesoMarketListed++; - session.Currency.Meso -= session.ServerTableMetadata.ConstantsTable.MesoMarketBasePrice; + session.Currency.Meso -= constants.MesoMarketBasePrice; session.Send(MesoMarketPacket.Create(listing)); session.Send(MesoMarketPacket.Quota(session.Player.Value.Account.MesoMarketListed, session.Player.Value.Account.MesoMarketPurchased)); } diff --git a/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs b/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs index cf21366ae..a9247bbf5 100644 --- a/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs @@ -32,9 +32,12 @@ private enum Command : byte { // ReSharper disable MemberCanBePrivate.Global public required NpcMetadataStorage NpcMetadata { private get; init; } public required ScriptMetadataStorage ScriptMetadata { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } // ReSharper restore All #endregion + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -237,7 +240,7 @@ private void HandleEnchant(GameSession session, IByteReader packet) { case ScriptEventType.EnchantSelect: case ScriptEventType.PeachySelect: if (!session.ScriptMetadata.TryGet(npcId, out ScriptMetadata? script) || - !script.States.TryGetValue(session.ServerTableMetadata.ConstantsTable.EnchantMasterScriptID, out ScriptState? state)) { + !script.States.TryGetValue(Constants.EnchantMasterScriptID, out ScriptState? state)) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/PartyHandler.cs b/Maple2.Server.Game/PacketHandlers/PartyHandler.cs index 2803d3a5c..c61280133 100644 --- a/Maple2.Server.Game/PacketHandlers/PartyHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/PartyHandler.cs @@ -36,9 +36,12 @@ private enum Command : byte { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required WorldClient World { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } // ReSharper restore All #endregion + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -285,7 +288,7 @@ private void HandleVoteKick(GameSession session, IByteReader packet) { return; } - if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(session.ServerTableMetadata.ConstantsTable.PartyVoteReadyDurationSeconds) + if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(Constants.PartyVoteReadyDurationSeconds) > DateTime.Now && session.Party.Party.Vote != null) { session.Send(PartyPacket.Error(PartyError.s_party_err_already_vote)); return; @@ -316,7 +319,7 @@ private void HandleReadyCheck(GameSession session) { return; } - if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(session.ServerTableMetadata.ConstantsTable.PartyVoteReadyDurationSeconds) > + if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(Constants.PartyVoteReadyDurationSeconds) > DateTime.Now && session.Party.Party.Vote != null) { session.Send(PartyPacket.Error(PartyError.s_party_err_already_vote)); return; diff --git a/Maple2.Server.Game/PacketHandlers/QuestHandler.cs b/Maple2.Server.Game/PacketHandlers/QuestHandler.cs index a23b4ba12..4bd673074 100644 --- a/Maple2.Server.Game/PacketHandlers/QuestHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/QuestHandler.cs @@ -36,9 +36,12 @@ private enum Command : byte { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required TableMetadataStorage TableMetadata { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } // ReSharper restore All #endregion + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -67,7 +70,7 @@ public override void Handle(GameSession session, IByteReader packet) { HandleGoToDungeon(session, packet); break; case Command.SkyFortress: - HandleSkyFortressTeleport(session); + HandleSkyFortressTeleport(session, Constants); break; case Command.MapleGuide: HandleMapleGuide(session, packet); @@ -265,13 +268,13 @@ private static void HandleCompleteFieldMission(GameSession session, IByteReader session.Quest.CompleteFieldMission(mission); } - private static void HandleSkyFortressTeleport(GameSession session) { - if (!session.Quest.TryGetQuest(session.ServerTableMetadata.ConstantsTable.FameContentsRequireQuestID, out Quest? quest) || quest.State != QuestState.Completed) { + private static void HandleSkyFortressTeleport(GameSession session, ConstantsTable constants) { + if (!session.Quest.TryGetQuest(constants.FameContentsRequireQuestID, out Quest? quest) || quest.State != QuestState.Completed) { return; } - session.Send(session.PrepareField(session.ServerTableMetadata.ConstantsTable.FameContentsSkyFortressGotoMapID, - session.ServerTableMetadata.ConstantsTable.FameContentsSkyFortressGotoPortalID) + session.Send(session.PrepareField(constants.FameContentsSkyFortressGotoMapID, + constants.FameContentsSkyFortressGotoPortalID) ? FieldEnterPacket.Request(session.Player) : FieldEnterPacket.Error(MigrationError.s_move_err_default)); } diff --git a/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs b/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs index 4572c9405..9f7e2fa44 100644 --- a/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs @@ -1,4 +1,5 @@ -using Maple2.Model.Game; +using Maple2.Database.Storage; +using Maple2.Model.Game; using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Server.Core.Constants; @@ -19,6 +20,14 @@ private enum Command : byte { Item = 10, } + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + // ReSharper restore All + #endregion + + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -47,11 +56,11 @@ private void HandleArena(GameSession session, IByteReader packet) { return; } - if (!session.NpcMetadata.TryGet(session.ServerTableMetadata.ConstantsTable.SystemShopNPCIDHonorToken, out NpcMetadata? npc)) { + if (!session.NpcMetadata.TryGet(Constants.SystemShopNPCIDHonorToken, out NpcMetadata? npc)) { return; } - session.Shop.Load(npc.Basic.ShopId, session.ServerTableMetadata.ConstantsTable.SystemShopNPCIDHonorToken); + session.Shop.Load(npc.Basic.ShopId, Constants.SystemShopNPCIDHonorToken); session.Send(SystemShopPacket.Arena()); } @@ -61,7 +70,7 @@ private void HandleFishing(GameSession session, IByteReader packet) { session.Shop.ClearActiveShop(); return; } - if (!session.NpcMetadata.TryGet(session.ServerTableMetadata.ConstantsTable.SystemShopNPCIDFishing, out NpcMetadata? npc)) { + if (!session.NpcMetadata.TryGet(Constants.SystemShopNPCIDFishing, out NpcMetadata? npc)) { return; } @@ -76,7 +85,7 @@ private void HandleMentee(GameSession session, IByteReader packet) { return; } - if (!session.NpcMetadata.TryGet(session.ServerTableMetadata.ConstantsTable.SystemShopNPCIDMentee, out NpcMetadata? npc)) { + if (!session.NpcMetadata.TryGet(Constants.SystemShopNPCIDMentee, out NpcMetadata? npc)) { return; } @@ -91,7 +100,7 @@ private void HandleMentor(GameSession session, IByteReader packet) { return; } - if (!session.NpcMetadata.TryGet(session.ServerTableMetadata.ConstantsTable.SystemShopNPCIDMentor, out NpcMetadata? npc)) { + if (!session.NpcMetadata.TryGet(Constants.SystemShopNPCIDMentor, out NpcMetadata? npc)) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs b/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs index a2db64fef..af621416f 100644 --- a/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs @@ -31,9 +31,12 @@ private enum Command : byte { public required MapMetadataStorage MapMetadata { private get; init; } public required MapEntityStorage EntityMetadata { private get; init; } public required WorldMapGraphStorage WorldMapGraph { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } // ReSharper restore All #endregion + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); @@ -136,12 +139,12 @@ private void HandleMeretAirTaxi(GameSession session, IByteReader packet) { return; } - if (session.Currency.Meret < session.ServerTableMetadata.ConstantsTable.MeratAirTaxiPrice) { + if (session.Currency.Meret < Constants.MeratAirTaxiPrice) { session.Send(NoticePacket.MessageBox(StringCode.s_err_lack_merat)); return; } - session.Currency.Meret -= session.ServerTableMetadata.ConstantsTable.MeratAirTaxiPrice; + session.Currency.Meret -= Constants.MeratAirTaxiPrice; session.Send(session.PrepareField(mapId) ? FieldEnterPacket.Request(session.Player) diff --git a/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs b/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs index 68a17c7d5..ce5b7dea7 100644 --- a/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs @@ -22,9 +22,12 @@ public class UserChatHandler : FieldPacketHandler { // ReSharper disable MemberCanBePrivate.Global public required WorldClient World { private get; init; } public required GameStorage GameStorage { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } // ReSharper restore All #endregion + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(GameSession session, IByteReader packet) { if (session.Field is null) return; var type = packet.Read(); @@ -180,7 +183,7 @@ private void HandleWorld(GameSession session, string message, ICollection } session.Send(NoticePacket.Notice(NoticePacket.Flags.Alert | NoticePacket.Flags.Message, StringCode.s_worldchat_use_coupon)); } else { - int meretCost = session.ServerTableMetadata.ConstantsTable.MeratConsumeWorldChat; + int meretCost = Constants.MeratConsumeWorldChat; if (session.FindEvent(GameEventType.SaleChat).FirstOrDefault()?.Metadata.Data is SaleChat gameEvent) { meretCost -= (int) (meretCost * Convert.ToSingle(gameEvent.WorldChatDiscount) / 10000); } @@ -215,7 +218,7 @@ private void HandleChannel(GameSession session, string message, ICollection Player.Session.ServerTableMetadata.ConstantsTable; + public GameSession(TcpClient tcpClient, GameServer server, IComponentContext context) : base(tcpClient) { this.server = server; State = SessionState.ChangeMap; @@ -434,7 +436,7 @@ private bool PrepareFieldInternal(int mapId, out FieldManager? newField, int por Player.Dispose(); Player = Field.SpawnPlayer(this, Player, portalId, position, rotation); Config.Skill.UpdatePassiveBuffs(); - Player.Buffs.LoadFieldBuffs(Player.Session.ServerTableMetadata.ConstantsTable.shadowWorldBuffHpUp, Player.Session.ServerTableMetadata.ConstantsTable.shadowWorldBuffMoveProtect); + Player.Buffs.LoadFieldBuffs(Constants.shadowWorldBuffHpUp, Constants.shadowWorldBuffMoveProtect); Player.CheckRegen(); return true; @@ -490,7 +492,7 @@ public bool EnterField() { Config.LoadRevival(); Config.LoadStatAttributes(); Config.LoadSkillPoints(); - Player.Buffs.LoadFieldBuffs(Player.Session.ServerTableMetadata.ConstantsTable.shadowWorldBuffHpUp, Player.Session.ServerTableMetadata.ConstantsTable.shadowWorldBuffMoveProtect); + Player.Buffs.LoadFieldBuffs(Constants.shadowWorldBuffHpUp, Constants.shadowWorldBuffMoveProtect); TimeEventResponse globalEventResponse = World.TimeEvent(new TimeEventRequest { GetGlobalPortal = new TimeEventRequest.Types.GetGlobalPortal(), diff --git a/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs b/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs index 2a863461d..87047fd05 100644 --- a/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs +++ b/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs @@ -49,6 +49,8 @@ private enum Command : byte { // ReSharper restore All #endregion + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + public override void Handle(LoginSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -59,15 +61,13 @@ public override void Handle(LoginSession session, IByteReader packet) { HandleCreate(session, packet); break; case Command.Delete: - HandleDelete(session, packet, ServerTableMetadata.ConstantsTable.CharacterDestroyDivisionLevel, - ServerTableMetadata.ConstantsTable.CharacterDestroyWaitSecond); + HandleDelete(session, packet); break; case Command.CancelDelete: HandleCancelDelete(session, packet); break; case Command.ConfirmDelete: - HandleDelete(session, packet, ServerTableMetadata.ConstantsTable.CharacterDestroyDivisionLevel, - ServerTableMetadata.ConstantsTable.CharacterDestroyWaitSecond); + HandleDelete(session, packet); break; default: throw new ArgumentException($"Invalid CHARACTER_MANAGEMENT type {command}"); @@ -201,7 +201,7 @@ private void HandleCreate(LoginSession session, IByteReader packet) { session.CreateCharacter(character, outfits); } - private void HandleDelete(LoginSession session, IByteReader packet, int characterDestroyDivisionLevel, int characterDestroyWaitSecond) { + private void HandleDelete(LoginSession session, IByteReader packet) { long characterId = packet.ReadLong(); using GameStorage.Request db = GameStorage.Context(); @@ -221,8 +221,8 @@ private void HandleDelete(LoginSession session, IByteReader packet, int characte return; } - if (character.Level >= characterDestroyDivisionLevel) { - character.DeleteTime = DateTimeOffset.UtcNow.AddSeconds(characterDestroyWaitSecond).ToUnixTimeSeconds(); + if (character.Level >= Constants.CharacterDestroyDivisionLevel) { + character.DeleteTime = DateTimeOffset.UtcNow.AddSeconds(Constants.CharacterDestroyWaitSecond).ToUnixTimeSeconds(); if (db.UpdateDelete(session.AccountId, characterId, character.DeleteTime)) { session.Send(CharacterListPacket.BeginDelete(characterId, character.DeleteTime)); } else { diff --git a/Maple2.Server.World/Containers/PartyLookup.cs b/Maple2.Server.World/Containers/PartyLookup.cs index a1f774b46..39b11b013 100644 --- a/Maple2.Server.World/Containers/PartyLookup.cs +++ b/Maple2.Server.World/Containers/PartyLookup.cs @@ -4,6 +4,7 @@ using Maple2.Model.Error; using Maple2.Model.Game; using Maple2.Model.Game.Party; +using Maple2.Model.Metadata; namespace Maple2.Server.World.Containers; @@ -11,24 +12,22 @@ public class PartyLookup : IDisposable { private readonly ChannelClientLookup channelClients; private readonly PlayerInfoLookup playerLookup; private readonly PartySearchLookup partySearchLookup; - private ServerTableMetadataStorage serverTableMetadataStorage; + private readonly ServerTableMetadataStorage serverTableMetadata; private readonly ConcurrentDictionary parties; private int nextPartyId = 1; + private ConstantsTable Constants => serverTableMetadata.ConstantsTable; - public PartyLookup(ChannelClientLookup channelClients, PlayerInfoLookup playerLookup, PartySearchLookup partySearchLookup) { + public PartyLookup(ChannelClientLookup channelClients, PlayerInfoLookup playerLookup, PartySearchLookup partySearchLookup, ServerTableMetadataStorage serverTableMetadata) { this.channelClients = channelClients; this.playerLookup = playerLookup; this.partySearchLookup = partySearchLookup; + this.serverTableMetadata = serverTableMetadata; parties = new ConcurrentDictionary(); } - public void InjectDependencies(ServerTableMetadataStorage serverTableMetadataStorage) { - this.serverTableMetadataStorage = serverTableMetadataStorage; - } - public void Dispose() { foreach (PartyManager manager in parties.Values) { manager.Dispose(); @@ -63,7 +62,7 @@ public PartyError Create(long leaderId, out int partyId) { } var party = new Party(partyId, leaderInfo.AccountId, leaderInfo.CharacterId, leaderInfo.Name); - var manager = new PartyManager(party, serverTableMetadataStorage.ConstantsTable.PartyVoteReadyDurationSeconds) { + var manager = new PartyManager(party, Constants.PartyVoteReadyDurationSeconds) { ChannelClients = channelClients, PartyLookup = this, }; diff --git a/Maple2.Server.World/Program.cs b/Maple2.Server.World/Program.cs index 7a7a954b0..1832966fe 100644 --- a/Maple2.Server.World/Program.cs +++ b/Maple2.Server.World/Program.cs @@ -87,9 +87,7 @@ var channelLookup = e.Context.Resolve(); var playerInfoLookup = e.Context.Resolve(); var partyLookup = e.Context.Resolve(); - var serverTableMetadataStorage = e.Context.Resolve(); channelLookup.InjectDependencies(e.Instance, playerInfoLookup); - partyLookup.InjectDependencies(serverTableMetadataStorage); }) .SingleInstance(); }); diff --git a/Maple2.Server.World/WorldServer.cs b/Maple2.Server.World/WorldServer.cs index 3301f16ce..6f29e35c1 100644 --- a/Maple2.Server.World/WorldServer.cs +++ b/Maple2.Server.World/WorldServer.cs @@ -36,6 +36,8 @@ public class WorldServer { private readonly LoginClient login; + private ConstantsTable Constants => serverTableMetadata.ConstantsTable; + public WorldServer(GameStorage gameStorage, ChannelClientLookup channelClients, ServerTableMetadataStorage serverTableMetadata, GlobalPortalLookup globalPortalLookup, WorldBossLookup worldBossLookup, PlayerInfoLookup playerInfoLookup, LoginClient login, ItemMetadataStorage itemMetadata) { this.gameStorage = gameStorage; this.channelClients = channelClients; @@ -422,7 +424,7 @@ public void FieldPlotExpiryCheck() { SetPlotAsPending(db, plot); forfeit = true; // mark as open when 3 days has passed since the expiry time - } else if (plot.OwnerId == 0 && plot.ExpiryTime + serverTableMetadata.ConstantsTable.UgcHomeSaleWaitingTime.TotalSeconds < DateTimeOffset.UtcNow.ToUnixTimeSeconds()) { + } else if (plot.OwnerId == 0 && plot.ExpiryTime + Constants.UgcHomeSaleWaitingTime.TotalSeconds < DateTimeOffset.UtcNow.ToUnixTimeSeconds()) { logger.Information("Marking plot {PlotId} as open (no owner)", plot.Id); db.SetPlotOpen(plot.Id); // Mark as open } else { @@ -449,7 +451,7 @@ public void FieldPlotExpiryCheck() { } // Schedule next check for the next soonest expiry - PlotInfo? nextPlot = db.GetSoonestPlotFromExpire(serverTableMetadata.ConstantsTable.UgcHomeSaleWaitingTime); + PlotInfo? nextPlot = db.GetSoonestPlotFromExpire(Constants.UgcHomeSaleWaitingTime); TimeSpan delay; if (nextPlot is not null) { DateTimeOffset nextExpiry = DateTimeOffset.FromUnixTimeSeconds(nextPlot.ExpiryTime); From 1b27496e09af4c74de8c99da12c3dac86ac10ce7 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Thu, 5 Mar 2026 09:23:46 -0600 Subject: [PATCH 18/26] Changes per feedback from Zin #2 --- Maple2.File.Ingest/Mapper/NpcMapper.cs | 14 +- .../Mapper/ServerTableMapper.cs | 165 ++++-------------- Maple2.File.Ingest/Utils/GenericHelper.cs | 96 ++++++++++ Maple2.Model/Game/Npc/Npc.cs | 7 +- Maple2.Model/Metadata/Constants.cs | 7 + Maple2.Model/Metadata/NpcMetadata.cs | 30 +--- Maple2.Server.Game/Commands/PlayerCommand.cs | 13 +- .../Manager/BlackMarketManager.cs | 4 + Maple2.Server.Game/Manager/BuddyManager.cs | 4 + Maple2.Server.Game/Manager/BuffManager.cs | 12 +- Maple2.Server.Game/Manager/ConfigManager.cs | 4 + Maple2.Server.Game/Manager/CurrencyManager.cs | 5 + .../Manager/ExperienceManager.cs | 9 +- .../Field/FieldManager/FieldManager.State.cs | 6 +- .../Field/FieldManager/FieldManager.cs | 3 +- .../Manager/ItemMergeManager.cs | 8 +- .../Manager/Items/InventoryManager.cs | 8 +- .../Manager/Items/StorageManager.cs | 8 +- Maple2.Server.Game/Manager/SkillManager.cs | 8 +- Maple2.Server.Game/Manager/TradeManager.cs | 9 +- .../MovementState.CleanupTask.cs | 9 +- .../Model/Field/Actor/FieldPet.cs | 5 + .../Model/Field/Actor/FieldPlayer.cs | 14 +- Maple2.Server.Game/Model/Field/Tombstone.cs | 9 +- .../PacketHandlers/BeautyHandler.cs | 3 +- .../PacketHandlers/ClubHandler.cs | 3 +- .../PacketHandlers/FunctionCubeHandler.cs | 9 +- .../PacketHandlers/GuildHandler.cs | 4 +- .../PacketHandlers/HomeBankHandler.cs | 4 +- .../PacketHandlers/HomeDoctorHandler.cs | 4 +- .../PacketHandlers/ItemLockHandler.cs | 4 +- .../PacketHandlers/JobHandler.cs | 11 +- .../PacketHandlers/MeretMarketHandler.cs | 3 +- .../PacketHandlers/MesoMarketHandler.cs | 3 +- .../PacketHandlers/NpcTalkHandler.cs | 3 +- .../PacketHandlers/PartyHandler.cs | 3 +- .../PacketHandlers/QuestHandler.cs | 3 +- .../PacketHandlers/SystemShopHandler.cs | 3 +- .../PacketHandlers/TaxiHandler.cs | 3 +- .../PacketHandlers/UserChatHandler.cs | 3 +- Maple2.Server.Game/Session/GameSession.cs | 6 +- .../CharacterManagementHandler.cs | 3 +- .../Containers/GlobalPortalManager.cs | 6 + Maple2.Server.World/Containers/PartyLookup.cs | 7 +- .../Containers/PartyManager.cs | 18 +- Maple2.Server.World/WorldServer.cs | 6 +- 46 files changed, 309 insertions(+), 260 deletions(-) create mode 100644 Maple2.File.Ingest/Utils/GenericHelper.cs diff --git a/Maple2.File.Ingest/Mapper/NpcMapper.cs b/Maple2.File.Ingest/Mapper/NpcMapper.cs index b8cee68af..943759be6 100644 --- a/Maple2.File.Ingest/Mapper/NpcMapper.cs +++ b/Maple2.File.Ingest/Mapper/NpcMapper.cs @@ -31,13 +31,13 @@ protected override IEnumerable Map() { AniSpeed: data.model.anispeed ), Distance: new NpcMetadataDistance( - data.distance.avoid, - data.distance.sight, - data.distance.sightHeightUP, - data.distance.sightHeightDown, - data.distance.customLastSightRadius, - data.distance.customLastSightHeightUp, - data.distance.customLastSightHeightDown + Avoid: data.distance.avoid, + Sight: data.distance.sight, + SightHeightUp: data.distance.sightHeightUP, + SightHeightDown: data.distance.sightHeightDown, + LastSightRadius: data.distance.customLastSightRadius == 0 ? Constant.NpcLastSightRadius : data.distance.customLastSightRadius, + LastSightHeightUp: data.distance.customLastSightHeightUp == 0 ? Constant.NpcLastSightHeightUp : data.distance.customLastSightHeightUp, + LastSightHeightDown: data.distance.customLastSightHeightDown == 0 ? Constant.NpcLastSightHeightDown : data.distance.customLastSightHeightDown ), Skill: new NpcMetadataSkill( Entries: data.skill.ids.Select((skillId, i) => diff --git a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs index 50a6a6df3..514e96d74 100644 --- a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs +++ b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs @@ -2149,146 +2149,51 @@ private ConstantsTable ParseConstants() { var constants = new ConstantsTable(); Dictionary propertyLookup = typeof(ConstantsTable).GetProperties() .ToDictionary(p => p.Name.Trim(), p => p, StringComparer.OrdinalIgnoreCase); - foreach ((string key, Constants.Key constant) in parser.ParseConstants()) { string trimmedKey = key.Trim(); if (!propertyLookup.TryGetValue(trimmedKey, out PropertyInfo? property)) continue; - string cleanValue = CleanConstantsInput( - constant.value.Trim(), - trimmedKey, - property.PropertyType - ); - SetValue(property, constants, cleanValue); + string cleanValue = CleanInput(constant.value.Trim(), trimmedKey, property.PropertyType); + GenericHelper.SetValue(property, constants, cleanValue); } return constants; - } - private string CleanConstantsInput(string input, string propName, Type type) { - // check if string contains the ending 'f' for float designation, strip it if it does. - if (type == typeof(float) && input.Contains('f')) { - input = input.TrimEnd('f', 'F'); - } - if (type == typeof(bool)) { - // 1 does not automatically equate to true during bool conversion - if (input == "1") { - input = "true"; - } - // 0 does not automatically equate to false during bool conversion - if (input == "0") { - input = "false"; + string CleanInput(string input, string propName, Type type) { + // check if string contains the ending 'f' for float designation, strip it if it does. + if (type == typeof(float) && input.Contains('f')) { + input = input.TrimEnd('f', 'F'); } - } - if (type == typeof(TimeSpan)) { - // Special case - dashes (-) are used instead of colons (:) - if (propName == "DailyTrophyResetDate") { - input = input.Replace('-', ':'); - } - // Stored as 0.1 for 100ms - if (propName == "GlobalCubeSkillIntervalTime") { - input = $"0:0:{input}"; - } - // Stored as an int value, convert to friendly input string for TimeSpan parsing - if (propName == "UgcHomeSaleWaitingTime") { - int.TryParse(input, out int result); - input = TimeSpan.FromSeconds(result).ToString(); // TODO: may not be correct conversion to TimeSpan + if (type == typeof(bool)) { + // 1 does not automatically equate to true during bool conversion + if (input == "1") { + input = "true"; + } + // 0 does not automatically equate to false during bool conversion + if (input == "0") { + input = "false"; + } } - } - if (type == typeof(int)) { - // Remove prefix 0 on integers since they do not convert properly - if (input.Length > 1 && input[0] == '0') { - input = input.Remove(0, 1); + if (type == typeof(TimeSpan)) { + // Special case - dashes (-) are used instead of colons (:) + if (propName == "DailyTrophyResetDate") { + input = input.Replace('-', ':'); + } + // Stored as 0.1 for 100ms + if (propName == "GlobalCubeSkillIntervalTime") { + input = $"0:0:{input}"; + } + // Stored as an int value, convert to friendly input string for TimeSpan parsing + if (propName == "UgcHomeSaleWaitingTime") { + int.TryParse(input, out int result); + input = TimeSpan.FromSeconds(result).ToString(); // TODO: may not be correct conversion to TimeSpan + } } - } - return input; - } - - private void SetValue(PropertyInfo prop, object? obj, object? value) { - if (obj == null && value == null || value == null) return; - HandleNonIConvertibleTypes(prop, ref value); - if (value == null) return; - if (typeof(IConvertible).IsAssignableFrom(prop.PropertyType)) { - TryParseObject(prop.PropertyType, value, out object? result); - prop.SetValue(obj, result); - return; - } - prop.SetValue(obj, value); - } - - private object? HandleNonIConvertibleTypes(PropertyInfo prop, ref object? value) { - if (value == null) return value; - // Handle TimeSpan type - if (prop.PropertyType == typeof(TimeSpan)) { - TimeSpan.TryParse((string) value, CultureInfo.InvariantCulture, out TimeSpan val); - value = val; - } - // Handle array types (int[], short[], etc.) - if (prop.PropertyType.IsArray) { - var elementType = prop.PropertyType.GetElementType(); - if (elementType == null) return value; - string[] segments = ((string)value).Split(','); - Array destinationArray = Array.CreateInstance(elementType, segments.Length); - for (int i = 0; i < segments.Length; i++) { - TryParseObject(elementType, segments[i].Trim(), out object? parseResult); - destinationArray.SetValue(parseResult ?? default, i); + if (type == typeof(int)) { + // Remove prefix 0 on integers since they do not convert properly + if (input.Length > 1 && input[0] == '0') { + input = input.Remove(0, 1); + } } - value = destinationArray; - } - // Handle Vector3 type - if (prop.PropertyType == typeof(Vector3)) { - string[] parts = ((string) value).Split(','); - if (parts.Length != 3) return value; - float.TryParse(parts[0], CultureInfo.InvariantCulture, out float x); - float.TryParse(parts[1], CultureInfo.InvariantCulture, out float y); - float.TryParse(parts[2], CultureInfo.InvariantCulture, out float z); - value = new Vector3(x, y, z); - } - return value; - } - - private bool TryParseObject(Type? elementType, object? input, out object? result) { - if (elementType == null || input == null) { - result = null; - return false; - } - - string? inputString = Convert.ToString(input, CultureInfo.InvariantCulture); - - // No TryParse method exists for a string, use the result directly. - if (elementType == typeof(string)) { - result = inputString; - return true; - } - - Type[] argTypes = { - typeof(string), - typeof(IFormatProvider), - elementType.MakeByRefType() - }; - - var method = elementType.GetMethod("TryParse", - BindingFlags.Public | BindingFlags.Static, - null, argTypes, null); - if (method != null) { - object[] args = [inputString, CultureInfo.InvariantCulture, null]; - bool success = (bool)method.Invoke(null, args); - result = args[2]; - return success; + return input; } - - // Fallback without CulturueInfo provided, in case the type does not have a CultureInfo overload. - Type[] simpleArgs = { typeof(string), elementType.MakeByRefType() }; - method = elementType.GetMethod("TryParse", - BindingFlags.Public | BindingFlags.Static, - null, simpleArgs, null); - if (method != null) { - object[] args = { inputString, null }; - bool success = (bool) method.Invoke(null, args); - result = args[1]; - return success; - } - - - result = null; - return false; } } diff --git a/Maple2.File.Ingest/Utils/GenericHelper.cs b/Maple2.File.Ingest/Utils/GenericHelper.cs new file mode 100644 index 000000000..a01f96150 --- /dev/null +++ b/Maple2.File.Ingest/Utils/GenericHelper.cs @@ -0,0 +1,96 @@ +using System.Globalization; +using System.Numerics; +using System.Reflection; + +namespace Maple2.File.Ingest.Utils; +public static class GenericHelper { + public static void SetValue(PropertyInfo prop, object? obj, object? value) { + if (obj == null && value == null || value == null) return; + HandleNonIConvertibleTypes(prop, ref value); + if (value == null) return; + if (typeof(IConvertible).IsAssignableFrom(prop.PropertyType)) { + TryParseObject(prop.PropertyType, value, out object? result); + prop.SetValue(obj, result); + return; + } + prop.SetValue(obj, value); + } + + private static object? HandleNonIConvertibleTypes(PropertyInfo prop, ref object? value) { + if (value == null) return value; + // Handle TimeSpan type + if (prop.PropertyType == typeof(TimeSpan)) { + TimeSpan.TryParse((string) value, CultureInfo.InvariantCulture, out TimeSpan val); + value = val; + } + // Handle array types (int[], short[], etc.) + if (prop.PropertyType.IsArray) { + var elementType = prop.PropertyType.GetElementType(); + if (elementType == null) return value; + string[] segments = ((string) value).Split(','); + Array destinationArray = Array.CreateInstance(elementType, segments.Length); + for (int i = 0; i < segments.Length; i++) { + TryParseObject(elementType, segments[i].Trim(), out object? parseResult); + destinationArray.SetValue(parseResult ?? default, i); + } + value = destinationArray; + } + // Handle Vector3 type + if (prop.PropertyType == typeof(Vector3)) { + string[] parts = ((string) value).Split(','); + if (parts.Length != 3) return value; + float.TryParse(parts[0], CultureInfo.InvariantCulture, out float x); + float.TryParse(parts[1], CultureInfo.InvariantCulture, out float y); + float.TryParse(parts[2], CultureInfo.InvariantCulture, out float z); + value = new Vector3(x, y, z); + } + return value; + } + + private static bool TryParseObject(Type? elementType, object? input, out object? result) { + if (elementType == null || input == null) { + result = null; + return false; + } + + string inputString = Convert.ToString(input, CultureInfo.InvariantCulture)!; + + // No TryParse method exists for a string, use the result directly. + if (elementType == typeof(string)) { + result = inputString; + return true; + } + + Type[] argTypes = { + typeof(string), + typeof(IFormatProvider), + elementType.MakeByRefType() + }; + + var method = elementType.GetMethod("TryParse", + BindingFlags.Public | BindingFlags.Static, + null, argTypes, null); + if (method != null) { + object[] args = [inputString, CultureInfo.InvariantCulture, null!]; + bool success = (bool) method.Invoke(null, args)!; + result = args[2]; + return success; + } + + // Fallback without CulturueInfo provided, in case the type does not have a CultureInfo overload. + Type[] simpleArgs = { typeof(string), elementType.MakeByRefType() }; + method = elementType.GetMethod("TryParse", + BindingFlags.Public | BindingFlags.Static, + null, simpleArgs, null); + if (method != null) { + object[] args = { inputString, null! }; + bool success = (bool)method.Invoke(null, args)!; + result = args[1]; + return success; + } + + + result = null; + return false; + } +} diff --git a/Maple2.Model/Game/Npc/Npc.cs b/Maple2.Model/Game/Npc/Npc.cs index fc176815c..d135d541b 100644 --- a/Maple2.Model/Game/Npc/Npc.cs +++ b/Maple2.Model/Game/Npc/Npc.cs @@ -10,11 +10,8 @@ public class Npc { public bool IsBoss => Metadata.Basic.Friendly == 0 && Metadata.Basic.Class >= 3; - public Npc(NpcMetadata metadata, AnimationMetadata? animation, float constLastSightRadius, float constLastSightHeightUp, float constLastSightHeightDown) { - float lastSightRadius = metadata.Distance.LastSightRadius == 0 ? constLastSightRadius : metadata.Distance.LastSightRadius; - float lastSightHeightUp = metadata.Distance.LastSightHeightUp == 0 ? constLastSightHeightUp : metadata.Distance.LastSightHeightUp; - float lastSightHeightDown = metadata.Distance.LastSightHeightDown == 0 ? constLastSightHeightDown : metadata.Distance.LastSightHeightDown; - Metadata = new NpcMetadata(metadata, lastSightRadius, lastSightHeightUp, lastSightHeightDown); + public Npc(NpcMetadata metadata, AnimationMetadata? animation) { + Metadata = metadata; Animations = animation?.Sequences ?? new Dictionary(); } } diff --git a/Maple2.Model/Metadata/Constants.cs b/Maple2.Model/Metadata/Constants.cs index 48154f1e4..881d9d210 100644 --- a/Maple2.Model/Metadata/Constants.cs +++ b/Maple2.Model/Metadata/Constants.cs @@ -203,6 +203,13 @@ public static class Constant { public static readonly bool BlockLoginWithMismatchedMachineId = false; public static readonly int DefaultMaxCharacters = 4; #endregion + + // TODO: Remove once NpcMetadataDistance handles these at runtime, since they are now in DB and parsed through file ingest. + #region Server table/constants.xml + public static readonly float NpcLastSightRadius = 0f; + public static readonly float NpcLastSightHeightUp = 0f; + public static readonly float NpcLastSightHeightDown = 0f; + #endregion } #pragma warning restore IDE1006 // Naming Styles diff --git a/Maple2.Model/Metadata/NpcMetadata.cs b/Maple2.Model/Metadata/NpcMetadata.cs index fca9752e6..55947b432 100644 --- a/Maple2.Model/Metadata/NpcMetadata.cs +++ b/Maple2.Model/Metadata/NpcMetadata.cs @@ -1,6 +1,4 @@ -using System.ComponentModel.Design; -using System.Numerics; -using System.Text.Json.Serialization; +using System.Numerics; using Maple2.Model.Enum; namespace Maple2.Model.Metadata; @@ -19,14 +17,7 @@ public record NpcMetadata( NpcMetadataAction Action, NpcMetadataDead Dead, NpcMetadataCorpse? Corpse, - NpcMetadataLookAtTarget LookAtTarget) : ISearchResult { - public NpcMetadata(NpcMetadata other, float lastSightRadius, float lastSightHeightUp, float lastSightHeightDown) : this(other.Id, - other.Name, other.AiPath, other.Model, other.Stat, other.Basic, other.Distance, other.Skill, other.Property, other.DropInfo, - other.Action, other.Dead, other.Corpse, other.LookAtTarget) { - Distance = new NpcMetadataDistance(Distance.Avoid, Distance.Sight, Distance.SightHeightUp, - Distance.SightHeightDown, lastSightRadius, lastSightHeightUp, lastSightHeightDown); - } -} + NpcMetadataLookAtTarget LookAtTarget) : ISearchResult; public record NpcMetadataModel( string Name, @@ -44,19 +35,10 @@ public record NpcMetadataDistance( float Avoid, float Sight, float SightHeightUp, - float SightHeightDown) { - [JsonConstructor] - public NpcMetadataDistance(float avoid, float sight, float sightHeightUp, float sightHeightDown, float lastSightRadius, - float lastSightHeightUp, float lastSightHeightDown) : this(avoid, sight, sightHeightUp, sightHeightDown) { - LastSightRadius = lastSightRadius; - LastSightHeightUp = lastSightHeightUp; - LastSightHeightDown = lastSightHeightDown; - } - - public float LastSightRadius { get; private set; } - public float LastSightHeightUp { get; private set; } - public float LastSightHeightDown { get; private set; } -} + float SightHeightDown, + float LastSightRadius, + float LastSightHeightUp, + float LastSightHeightDown); public record NpcMetadataSkill( NpcMetadataSkill.Entry[] Entries, diff --git a/Maple2.Server.Game/Commands/PlayerCommand.cs b/Maple2.Server.Game/Commands/PlayerCommand.cs index 7140cb035..b11135991 100644 --- a/Maple2.Server.Game/Commands/PlayerCommand.cs +++ b/Maple2.Server.Game/Commands/PlayerCommand.cs @@ -115,7 +115,12 @@ private void Handle(InvocationContext ctx, MasteryType masteryType, int level) { private class LevelCommand : Command { private readonly GameSession session; + + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion public LevelCommand(GameSession session) : base("level", "Set player level.") { this.session = session; @@ -181,7 +186,12 @@ private void Handle(InvocationContext ctx, long exp) { private class PrestigeCommand : Command { private readonly GameSession session; + + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion public PrestigeCommand(GameSession session) : base("prestige", "Sets prestige level") { this.session = session; @@ -211,7 +221,6 @@ private void Handle(InvocationContext ctx, int level) { private class JobCommand : Command { private readonly GameSession session; - private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; public JobCommand(GameSession session) : base("job", "Set player job.") { this.session = session; @@ -331,7 +340,7 @@ private void JobAdvance(Job job) { session.Player.Buffs.Clear(); session.Player.Buffs.Initialize(); - session.Player.Buffs.LoadFieldBuffs(Constants.shadowWorldBuffHpUp, Constants.shadowWorldBuffMoveProtect); + session.Player.Buffs.LoadFieldBuffs(); session.Stats.Refresh(); session.Field?.Broadcast(JobPacket.Advance(session.Player, session.Config.Skill.SkillInfo)); } diff --git a/Maple2.Server.Game/Manager/BlackMarketManager.cs b/Maple2.Server.Game/Manager/BlackMarketManager.cs index ab3fcacf2..b2314d9c2 100644 --- a/Maple2.Server.Game/Manager/BlackMarketManager.cs +++ b/Maple2.Server.Game/Manager/BlackMarketManager.cs @@ -16,7 +16,11 @@ namespace Maple2.Server.Game.Manager; public sealed class BlackMarketManager { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion private readonly ILogger logger = Log.Logger.ForContext(); diff --git a/Maple2.Server.Game/Manager/BuddyManager.cs b/Maple2.Server.Game/Manager/BuddyManager.cs index cb03d11f5..96c922e93 100644 --- a/Maple2.Server.Game/Manager/BuddyManager.cs +++ b/Maple2.Server.Game/Manager/BuddyManager.cs @@ -17,7 +17,11 @@ namespace Maple2.Server.Game.Manager; public class BuddyManager : IDisposable { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion private readonly IDictionary buddies; private readonly IDictionary blocked; diff --git a/Maple2.Server.Game/Manager/BuffManager.cs b/Maple2.Server.Game/Manager/BuffManager.cs index 3809822b4..5941c4a88 100644 --- a/Maple2.Server.Game/Manager/BuffManager.cs +++ b/Maple2.Server.Game/Manager/BuffManager.cs @@ -60,11 +60,11 @@ public void Clear() { } } - public void LoadFieldBuffs(int shadowWorldBuffHpUp, int shadowWorldBuffMoveProtect) { + public void LoadFieldBuffs() { // Lapenshards // Game Events // Prestige - EnterField(shadowWorldBuffHpUp, shadowWorldBuffMoveProtect); + EnterField(); if (Actor is FieldPlayer player) { player.Session.Config.RefreshPremiumClubBuffs(); } @@ -438,7 +438,7 @@ public void LeaveField() { Remove(buffsToRemove.ToArray()); } - private void EnterField(int shadowWorldBuffHpUp, int shadowWorldBuffMoveProtect) { + private void EnterField() { foreach (MapEntranceBuff buff in Actor.Field.Metadata.EntranceBuffs) { AddBuff(Actor, Actor, buff.Id, buff.Level, Actor.Field.FieldTick); } @@ -458,8 +458,10 @@ private void EnterField(int shadowWorldBuffHpUp, int shadowWorldBuffMoveProtect) } if (Actor.Field.Metadata.Property.Region == MapRegion.ShadowWorld) { - AddBuff(Actor, Actor, shadowWorldBuffHpUp, 1, Actor.Field.FieldTick); - AddBuff(Actor, Actor, shadowWorldBuffMoveProtect, 1, Actor.Field.FieldTick); + if (Actor is FieldPlayer player) { + AddBuff(Actor, Actor, player.Session.ServerTableMetadata.ConstantsTable.shadowWorldBuffHpUp, 1, Actor.Field.FieldTick); + AddBuff(Actor, Actor, player.Session.ServerTableMetadata.ConstantsTable.shadowWorldBuffMoveProtect, 1, Actor.Field.FieldTick); + } } } diff --git a/Maple2.Server.Game/Manager/ConfigManager.cs b/Maple2.Server.Game/Manager/ConfigManager.cs index 0e15eb24a..56e460cac 100644 --- a/Maple2.Server.Game/Manager/ConfigManager.cs +++ b/Maple2.Server.Game/Manager/ConfigManager.cs @@ -18,7 +18,11 @@ public class ConfigManager { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion private readonly IDictionary keyBinds; private short activeHotBar; diff --git a/Maple2.Server.Game/Manager/CurrencyManager.cs b/Maple2.Server.Game/Manager/CurrencyManager.cs index e0465e0f5..bb145dd90 100644 --- a/Maple2.Server.Game/Manager/CurrencyManager.cs +++ b/Maple2.Server.Game/Manager/CurrencyManager.cs @@ -9,7 +9,12 @@ namespace Maple2.Server.Game.Manager; public class CurrencyManager { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private Currency Currency => session.Player.Value.Currency; public CurrencyManager(GameSession session) { diff --git a/Maple2.Server.Game/Manager/ExperienceManager.cs b/Maple2.Server.Game/Manager/ExperienceManager.cs index fe8ed46ec..0cca2aa36 100644 --- a/Maple2.Server.Game/Manager/ExperienceManager.cs +++ b/Maple2.Server.Game/Manager/ExperienceManager.cs @@ -13,6 +13,13 @@ namespace Maple2.Server.Game.Manager; public sealed class ExperienceManager { private readonly GameSession session; + + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private long Exp { get => session.Player.Value.Character.Exp; set => session.Player.Value.Character.Exp = value; @@ -52,8 +59,6 @@ public long PrestigeCurrentExp { private int ChainKillCount { get; set; } - private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; - public ExperienceManager(GameSession session) { this.session = session; Init(); diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs index d078b2de7..d6f90d700 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs @@ -143,8 +143,7 @@ public FieldPlayer SpawnPlayer(GameSession session, Player player, int portalId AnimationMetadata? animation = NpcMetadata.GetAnimation(npc.Model.Name); string aiPath = disableAi ? string.Empty : npc.AiPath; - var fieldNpc = new FieldNpc(this, NextLocalId(), agent, new Npc(npc, animation, Constants.NpcLastingSightRadius, - Constants.NpcLastingSightHeightUp, Constants.NpcLastingSightHeightDown), aiPath, + var fieldNpc = new FieldNpc(this, NextLocalId(), agent, new Npc(npc, animation), aiPath, patrolDataUUID: spawnPointNpc?.PatrolData, spawnAnimation: spawnAnimation) { Owner = owner, Position = spawnPosition, @@ -183,8 +182,7 @@ public FieldPlayer SpawnPlayer(GameSession session, Player player, int portalId int objectId = player != null ? NextGlobalId() : NextLocalId(); AnimationMetadata? animation = NpcMetadata.GetAnimation(npc.Model.Name); - var fieldPet = new FieldPet(this, objectId, agent, new Npc(npc, animation, Constants.NpcLastingSightRadius, - Constants.NpcLastingSightHeightUp,Constants.NpcLastingSightHeightDown), + var fieldPet = new FieldPet(this, objectId, agent, new Npc(npc, animation), pet, petMetadata, Constant.PetFieldAiPath, player) { Owner = owner, Position = position, diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs index cafe62325..5583f5879 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs @@ -55,6 +55,7 @@ public partial class FieldManager : IField { public TriggerCache TriggerCache { get; init; } = null!; public Factory FieldFactory { get; init; } = null!; public IGraphicsContext DebugGraphicsContext { get; init; } = null!; + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion @@ -72,8 +73,6 @@ public partial class FieldManager : IField { private readonly List<(FieldPacketHandler handler, GameSession session, ByteReader reader)> queuedPackets; private bool initialized; - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public bool Disposed { get; private set; } private readonly ILogger logger = Log.Logger.ForContext(); diff --git a/Maple2.Server.Game/Manager/ItemMergeManager.cs b/Maple2.Server.Game/Manager/ItemMergeManager.cs index 2ed470dbe..4755bc21b 100644 --- a/Maple2.Server.Game/Manager/ItemMergeManager.cs +++ b/Maple2.Server.Game/Manager/ItemMergeManager.cs @@ -14,13 +14,17 @@ public sealed class ItemMergeManager { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private readonly ILogger logger = Log.Logger.ForContext(); private Item? upgradeItem; private Item? catalystItem; - private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; - public ItemMergeManager(GameSession session) { this.session = session; } diff --git a/Maple2.Server.Game/Manager/Items/InventoryManager.cs b/Maple2.Server.Game/Manager/Items/InventoryManager.cs index dedecfeb1..5d2b6f0b5 100644 --- a/Maple2.Server.Game/Manager/Items/InventoryManager.cs +++ b/Maple2.Server.Game/Manager/Items/InventoryManager.cs @@ -20,13 +20,17 @@ public class InventoryManager { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private readonly Dictionary tabs; private readonly List delete; private readonly ILogger logger = Log.Logger.ForContext(); - private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; - public InventoryManager(GameStorage.Request db, GameSession session) { this.session = session; tabs = new Dictionary(); diff --git a/Maple2.Server.Game/Manager/Items/StorageManager.cs b/Maple2.Server.Game/Manager/Items/StorageManager.cs index ac1487ac1..a38a2f5e3 100644 --- a/Maple2.Server.Game/Manager/Items/StorageManager.cs +++ b/Maple2.Server.Game/Manager/Items/StorageManager.cs @@ -15,11 +15,17 @@ public sealed class StorageManager : IDisposable { private const int BATCH_SIZE = 10; private readonly GameSession session; + + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private readonly ItemCollection items; private long mesos; private short expand; - private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; public StorageManager(GameSession session) { this.session = session; diff --git a/Maple2.Server.Game/Manager/SkillManager.cs b/Maple2.Server.Game/Manager/SkillManager.cs index 7adcd762b..15ffa5a7b 100644 --- a/Maple2.Server.Game/Manager/SkillManager.cs +++ b/Maple2.Server.Game/Manager/SkillManager.cs @@ -12,13 +12,17 @@ namespace Maple2.Server.Game.Manager; public class SkillManager { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public readonly SkillBook SkillBook; public readonly SkillInfo SkillInfo; private readonly ILogger logger = Log.ForContext(); - private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; - public SkillManager(GameSession session, SkillBook skillBook) { this.session = session; diff --git a/Maple2.Server.Game/Manager/TradeManager.cs b/Maple2.Server.Game/Manager/TradeManager.cs index 7e96e8707..e917e31a0 100644 --- a/Maple2.Server.Game/Manager/TradeManager.cs +++ b/Maple2.Server.Game/Manager/TradeManager.cs @@ -1,6 +1,7 @@ using Maple2.Model.Enum; using Maple2.Model.Game; using Maple2.Model.Metadata; +using Maple2.Server.Core.Network; using Maple2.Server.Game.Manager.Items; using Maple2.Server.Game.Packets; using Maple2.Server.Game.Session; @@ -21,9 +22,13 @@ private enum TradeState { private readonly Trader receiver; private TradeState state; - private readonly object mutex = new(); - + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global private ConstantsTable Constants => sender.Session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + + private readonly object mutex = new(); public TradeManager(GameSession sender, GameSession receiver) { this.sender = new Trader(sender); diff --git a/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs b/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs index 1808184d5..cef66f6c0 100644 --- a/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs +++ b/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs @@ -1,6 +1,7 @@ -using System.Numerics; -using Maple2.Model.Metadata; +using Maple2.Model.Metadata; +using Maple2.Server.Core.Network; using Maple2.Server.Game.Model.Enum; +using System.Numerics; using static Maple2.Server.Game.Model.ActorStateComponent.TaskState; namespace Maple2.Server.Game.Model.ActorStateComponent; @@ -11,7 +12,11 @@ public class NpcCleanupPatrolDataTask : NpcTask { private readonly FieldPlayer player; private readonly Vector3? lastPosition; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global private ConstantsTable Constants => player.Session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion public override bool CancelOnInterrupt => false; diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs b/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs index 7fc577060..52f7a4f46 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs @@ -3,6 +3,7 @@ using Maple2.Model.Enum; using Maple2.Model.Game; using Maple2.Model.Metadata; +using Maple2.Server.Core.Network; using Maple2.Server.Core.Packets; using Maple2.Server.Game.Manager.Field; using Maple2.Server.Game.Model.Skill; @@ -24,7 +25,11 @@ public sealed class FieldPet : FieldNpc { public int TamingPoint; private long tamingTick; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global private ConstantsTable Constants => Field.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion public FieldPet(FieldManager field, int objectId, DtCrowdAgent agent, Npc npc, Item pet, PetMetadata petMetadata, string aiPath, FieldPlayer? owner = null) : base(field, objectId, agent, npc, aiPath) { this.owner = owner; diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs b/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs index 3a6abb4d7..8287e2c60 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs @@ -1,20 +1,28 @@ -using System.Numerics; -using Maple2.Model.Enum; +using Maple2.Model.Enum; using Maple2.Model.Error; using Maple2.Model.Game; using Maple2.Model.Metadata; using Maple2.Model.Metadata.FieldEntity; +using Maple2.Server.Core.Network; using Maple2.Server.Game.Manager; using Maple2.Server.Game.Model.Skill; using Maple2.Server.Game.Packets; using Maple2.Server.Game.Session; using Maple2.Tools.Collision; using Maple2.Tools.Scheduler; +using System.Numerics; namespace Maple2.Server.Game.Model; public class FieldPlayer : Actor { public readonly GameSession Session; + + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => Session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public Vector3 LastGroundPosition; public override StatsManager Stats => Session.Stats; @@ -98,8 +106,6 @@ public AdminPermissions AdminPermissions { private readonly EventQueue scheduler; - private ConstantsTable Constants => Session.ServerTableMetadata.ConstantsTable; - public FieldPlayer(GameSession session, Player player) : base(session.Field!, player.ObjectId, player, session.NpcMetadata) { Session = session; Animation = Session.Animation; diff --git a/Maple2.Server.Game/Model/Field/Tombstone.cs b/Maple2.Server.Game/Model/Field/Tombstone.cs index 02debf679..e39eba637 100644 --- a/Maple2.Server.Game/Model/Field/Tombstone.cs +++ b/Maple2.Server.Game/Model/Field/Tombstone.cs @@ -7,6 +7,13 @@ namespace Maple2.Server.Game.Model; public class Tombstone : IByteSerializable { public readonly FieldPlayer Owner; + + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => Owner.Session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public int ObjectId => Owner.ObjectId; private byte hitsRemaining; public byte HitsRemaining { @@ -24,8 +31,6 @@ public byte HitsRemaining { public int Unknown1 { get; } = 1; public bool Unknown2 { get; } - private ConstantsTable Constants => Owner.Session.ServerTableMetadata.ConstantsTable; - public Tombstone(FieldPlayer owner, int totalDeaths) { Owner = owner; TotalHitCount = (byte) Math.Min(totalDeaths * Constants.hitPerDeadCount, diff --git a/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs b/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs index f31755a71..152c36d17 100644 --- a/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs @@ -27,11 +27,10 @@ public class BeautyHandler : FieldPacketHandler { public required TableMetadataStorage TableMetadata { private get; init; } public required NpcMetadataStorage NpcMetadata { private get; init; } public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - private enum Command : byte { Shop = 0, CreateBeauty = 3, diff --git a/Maple2.Server.Game/PacketHandlers/ClubHandler.cs b/Maple2.Server.Game/PacketHandlers/ClubHandler.cs index da01d5b69..5a866e8d7 100644 --- a/Maple2.Server.Game/PacketHandlers/ClubHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/ClubHandler.cs @@ -35,11 +35,10 @@ private enum Command : byte { public required WorldClient World { private get; init; } public required BanWordStorage BanWordStorage { private get; init; } public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { diff --git a/Maple2.Server.Game/PacketHandlers/FunctionCubeHandler.cs b/Maple2.Server.Game/PacketHandlers/FunctionCubeHandler.cs index 8bc5ae575..24e86e2cd 100644 --- a/Maple2.Server.Game/PacketHandlers/FunctionCubeHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/FunctionCubeHandler.cs @@ -18,6 +18,7 @@ public class FunctionCubeHandler : FieldPacketHandler { // ReSharper disable MemberCanBePrivate.Global public required FunctionCubeMetadataStorage FunctionCubeMetadataStorage { private get; init; } public required ServerTableMetadataStorage ServerTableMetadataStorage { private get; init; } + private ConstantsTable Constants => ServerTableMetadataStorage.ConstantsTable; // ReSharper restore All #endregion @@ -149,7 +150,7 @@ private void HandleNurturing(GameSession session, FieldFunctionInteract fieldCub // drop the item session.Field.DropItem(fieldCube.Position, fieldCube.Rotation, rewardItem, owner: session.Player, characterId: session.CharacterId); - nurturing.Feed(ServerTableMetadataStorage.ConstantsTable.NurturingEatGrowth); + nurturing.Feed(Constants.NurturingEatGrowth); db.UpdateNurturing(session.AccountId, fieldCube.InteractCube); session.Field.Broadcast(FunctionCubePacket.UpdateFunctionCube(fieldCube.InteractCube)); @@ -164,12 +165,12 @@ private void HandlePlayNurturing(GameSession session, Plot plot, FieldFunctionIn return; } - if (db.CountNurturingForAccount(cube.InteractCube.Metadata.Id, session.AccountId) >= ServerTableMetadataStorage.ConstantsTable.NurturingEatMaxCount) { + if (db.CountNurturingForAccount(cube.InteractCube.Metadata.Id, session.AccountId) >= Constants.NurturingEatMaxCount) { session.Send(NoticePacket.Message("You have already played with the maximum number of pets today. TODO: Find correct string id")); // TODO: Find correct string id return; } - if (!nurturing.Play(session.AccountId, ServerTableMetadataStorage.ConstantsTable.NurturingEatGrowth, ServerTableMetadataStorage.ConstantsTable.NurturingEatMaxCount)) { + if (!nurturing.Play(session.AccountId, Constants.NurturingEatGrowth, Constants.NurturingEatMaxCount)) { return; } @@ -217,7 +218,7 @@ private void HandlePlayNurturing(GameSession session, Plot plot, FieldFunctionIn return null; } - var mail = new Mail(ServerTableMetadataStorage.ConstantsTable.MailExpiryDays) { + var mail = new Mail(Constants.MailExpiryDays) { ReceiverId = ownerId, Type = MailType.System, Content = contentId, diff --git a/Maple2.Server.Game/PacketHandlers/GuildHandler.cs b/Maple2.Server.Game/PacketHandlers/GuildHandler.cs index 57714794f..18c18db35 100644 --- a/Maple2.Server.Game/PacketHandlers/GuildHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/GuildHandler.cs @@ -66,12 +66,10 @@ private enum Command : byte { public required TableMetadataStorage TableMetadata { private get; init; } public required BanWordStorage BanWordStorage { private get; init; } public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } - + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { diff --git a/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs b/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs index 67166ee36..f9cfa9ec9 100644 --- a/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs @@ -20,12 +20,10 @@ private enum Command : byte { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } - + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { diff --git a/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs b/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs index 29bcbce1d..4445496ba 100644 --- a/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs @@ -16,12 +16,10 @@ public class HomeDoctorHandler : FieldPacketHandler { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } - + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { if (session.Field is null) return; long time = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); diff --git a/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs b/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs index 69ed4263c..776a1f7c4 100644 --- a/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs @@ -22,12 +22,10 @@ private enum Command : byte { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } - + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { diff --git a/Maple2.Server.Game/PacketHandlers/JobHandler.cs b/Maple2.Server.Game/PacketHandlers/JobHandler.cs index 9464d381b..38fc316d8 100644 --- a/Maple2.Server.Game/PacketHandlers/JobHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/JobHandler.cs @@ -24,15 +24,6 @@ private enum Command : byte { AutoDistribute = 11, } - #region Autofac Autowired - // ReSharper disable MemberCanBePrivate.Global - public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } - - // ReSharper restore All - #endregion - - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -104,7 +95,7 @@ private void HandleAdvance(GameSession session, IByteReader packet) { session.Player.Buffs.Clear(); session.Player.Buffs.Initialize(); - session.Player.Buffs.LoadFieldBuffs(Constants.shadowWorldBuffHpUp, Constants.shadowWorldBuffMoveProtect); + session.Player.Buffs.LoadFieldBuffs(); session.Stats.Refresh(); session.Field.Broadcast(JobPacket.Advance(session.Player, session.Config.Skill.SkillInfo)); session.ConditionUpdate(ConditionType.job, codeLong: (int) session.NpcScript.JobCondition.ChangeToJobCode); diff --git a/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs b/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs index 72d0cb80c..0682a6d85 100644 --- a/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs @@ -22,11 +22,10 @@ public class MeretMarketHandler : FieldPacketHandler { // ReSharper disable MemberCanBePrivate.Global public required TableMetadataStorage TableMetadata { private get; init; } public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - private enum Command : byte { LoadPersonalListings = 11, LoadSales = 12, diff --git a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs index 817e22a4b..deb044282 100644 --- a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs @@ -28,11 +28,10 @@ private enum Command : byte { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { diff --git a/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs b/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs index a9247bbf5..7dafbd1ca 100644 --- a/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs @@ -33,11 +33,10 @@ private enum Command : byte { public required NpcMetadataStorage NpcMetadata { private get; init; } public required ScriptMetadataStorage ScriptMetadata { private get; init; } public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { diff --git a/Maple2.Server.Game/PacketHandlers/PartyHandler.cs b/Maple2.Server.Game/PacketHandlers/PartyHandler.cs index c61280133..7b80e18f9 100644 --- a/Maple2.Server.Game/PacketHandlers/PartyHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/PartyHandler.cs @@ -37,11 +37,10 @@ private enum Command : byte { // ReSharper disable MemberCanBePrivate.Global public required WorldClient World { private get; init; } public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { diff --git a/Maple2.Server.Game/PacketHandlers/QuestHandler.cs b/Maple2.Server.Game/PacketHandlers/QuestHandler.cs index 4bd673074..5c59c0fea 100644 --- a/Maple2.Server.Game/PacketHandlers/QuestHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/QuestHandler.cs @@ -37,11 +37,10 @@ private enum Command : byte { // ReSharper disable MemberCanBePrivate.Global public required TableMetadataStorage TableMetadata { private get; init; } public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { diff --git a/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs b/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs index 9f7e2fa44..fb3d0f49f 100644 --- a/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs @@ -23,11 +23,10 @@ private enum Command : byte { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { diff --git a/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs b/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs index af621416f..a70daf02a 100644 --- a/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs @@ -32,11 +32,10 @@ private enum Command : byte { public required MapEntityStorage EntityMetadata { private get; init; } public required WorldMapGraphStorage WorldMapGraph { private get; init; } public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); diff --git a/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs b/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs index ce5b7dea7..2ed7d7bc0 100644 --- a/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs @@ -23,11 +23,10 @@ public class UserChatHandler : FieldPacketHandler { public required WorldClient World { private get; init; } public required GameStorage GameStorage { private get; init; } public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(GameSession session, IByteReader packet) { if (session.Field is null) return; var type = packet.Read(); diff --git a/Maple2.Server.Game/Session/GameSession.cs b/Maple2.Server.Game/Session/GameSession.cs index 99ba3ff0e..d4644d6a6 100644 --- a/Maple2.Server.Game/Session/GameSession.cs +++ b/Maple2.Server.Game/Session/GameSession.cs @@ -110,8 +110,6 @@ public sealed partial class GameSession : Core.Network.Session { public RideManager Ride { get; set; } = null!; public MentoringManager Mentoring { get; set; } = null!; - private ConstantsTable Constants => Player.Session.ServerTableMetadata.ConstantsTable; - public GameSession(TcpClient tcpClient, GameServer server, IComponentContext context) : base(tcpClient) { this.server = server; State = SessionState.ChangeMap; @@ -436,7 +434,7 @@ private bool PrepareFieldInternal(int mapId, out FieldManager? newField, int por Player.Dispose(); Player = Field.SpawnPlayer(this, Player, portalId, position, rotation); Config.Skill.UpdatePassiveBuffs(); - Player.Buffs.LoadFieldBuffs(Constants.shadowWorldBuffHpUp, Constants.shadowWorldBuffMoveProtect); + Player.Buffs.LoadFieldBuffs(); Player.CheckRegen(); return true; @@ -492,7 +490,7 @@ public bool EnterField() { Config.LoadRevival(); Config.LoadStatAttributes(); Config.LoadSkillPoints(); - Player.Buffs.LoadFieldBuffs(Constants.shadowWorldBuffHpUp, Constants.shadowWorldBuffMoveProtect); + Player.Buffs.LoadFieldBuffs(); TimeEventResponse globalEventResponse = World.TimeEvent(new TimeEventRequest { GetGlobalPortal = new TimeEventRequest.Types.GetGlobalPortal(), diff --git a/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs b/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs index 87047fd05..6cd5bcda3 100644 --- a/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs +++ b/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs @@ -46,11 +46,10 @@ private enum Command : byte { public required ItemMetadataStorage ItemMetadata { private get; init; } public required TableMetadataStorage TableMetadata { private get; init; } public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion - private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; - public override void Handle(LoginSession session, IByteReader packet) { var command = packet.Read(); switch (command) { diff --git a/Maple2.Server.World/Containers/GlobalPortalManager.cs b/Maple2.Server.World/Containers/GlobalPortalManager.cs index bc09af40f..ce3705f9b 100644 --- a/Maple2.Server.World/Containers/GlobalPortalManager.cs +++ b/Maple2.Server.World/Containers/GlobalPortalManager.cs @@ -9,9 +9,15 @@ namespace Maple2.Server.World.Containers; public class GlobalPortalManager : IDisposable { + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + // ReSharper disable UnusedAutoPropertyAccessor.Global public required GameStorage GameStorage { get; init; } public required ServerTableMetadataStorage ServerTableMetadata { get; init; } public required ChannelClientLookup ChannelClients { get; init; } + // ReSharper restore All + // ReSharper restore UnusedAutoPropertyAccessor.Global + #endregion public readonly GlobalPortal Portal; public int Channel; diff --git a/Maple2.Server.World/Containers/PartyLookup.cs b/Maple2.Server.World/Containers/PartyLookup.cs index 39b11b013..0220242b2 100644 --- a/Maple2.Server.World/Containers/PartyLookup.cs +++ b/Maple2.Server.World/Containers/PartyLookup.cs @@ -9,15 +9,15 @@ namespace Maple2.Server.World.Containers; public class PartyLookup : IDisposable { + #region Autofac Autowired private readonly ChannelClientLookup channelClients; private readonly PlayerInfoLookup playerLookup; private readonly PartySearchLookup partySearchLookup; private readonly ServerTableMetadataStorage serverTableMetadata; - + #endregion private readonly ConcurrentDictionary parties; private int nextPartyId = 1; - private ConstantsTable Constants => serverTableMetadata.ConstantsTable; public PartyLookup(ChannelClientLookup channelClients, PlayerInfoLookup playerLookup, PartySearchLookup partySearchLookup, ServerTableMetadataStorage serverTableMetadata) { this.channelClients = channelClients; @@ -62,9 +62,10 @@ public PartyError Create(long leaderId, out int partyId) { } var party = new Party(partyId, leaderInfo.AccountId, leaderInfo.CharacterId, leaderInfo.Name); - var manager = new PartyManager(party, Constants.PartyVoteReadyDurationSeconds) { + var manager = new PartyManager(party) { ChannelClients = channelClients, PartyLookup = this, + ServerTableMetadata = serverTableMetadata }; if (!parties.TryAdd(partyId, manager)) { diff --git a/Maple2.Server.World/Containers/PartyManager.cs b/Maple2.Server.World/Containers/PartyManager.cs index a38467520..6532a099c 100644 --- a/Maple2.Server.World/Containers/PartyManager.cs +++ b/Maple2.Server.World/Containers/PartyManager.cs @@ -5,22 +5,30 @@ using Maple2.Model.Error; using Maple2.Model.Game; using Maple2.Model.Game.Party; +using Maple2.Model.Metadata; using Maple2.Server.Channel.Service; using ChannelClient = Maple2.Server.Channel.Service.Channel.ChannelClient; namespace Maple2.Server.World.Containers; public class PartyManager : IDisposable { + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + // ReSharper disable UnusedAutoPropertyAccessor.Global public required ChannelClientLookup ChannelClients { get; init; } public required PartyLookup PartyLookup { get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + // ReSharper restore All + // ReSharper restore UnusedAutoPropertyAccessor.Global + #endregion + public readonly Party Party; private readonly ConcurrentDictionary pendingInvites; - private readonly int partyVoteReadyDurationSeconds; - public PartyManager(Party party, int partyVoteReadyDurationSeconds) { + public PartyManager(Party party) { Party = party; pendingInvites = new ConcurrentDictionary(); - this.partyVoteReadyDurationSeconds = partyVoteReadyDurationSeconds; } public void Dispose() { @@ -284,7 +292,7 @@ public PartyError StartReadyCheck(long requestorId) { }); Task.Factory.StartNew(() => { - Thread.Sleep(TimeSpan.FromSeconds(partyVoteReadyDurationSeconds)); + Thread.Sleep(TimeSpan.FromSeconds(Constants.PartyVoteReadyDurationSeconds)); if (Party.Vote == null) { return; } @@ -396,7 +404,7 @@ public PartyError VoteKick(long requestorId, long targetId) { Task.Factory.StartNew(() => { // TODO: The duration is wrong. - Thread.Sleep(TimeSpan.FromSeconds(partyVoteReadyDurationSeconds)); + Thread.Sleep(TimeSpan.FromSeconds(Constants.PartyVoteReadyDurationSeconds)); if (Party.Vote == null) { return; } diff --git a/Maple2.Server.World/WorldServer.cs b/Maple2.Server.World/WorldServer.cs index 6f29e35c1..634dedf44 100644 --- a/Maple2.Server.World/WorldServer.cs +++ b/Maple2.Server.World/WorldServer.cs @@ -18,6 +18,7 @@ namespace Maple2.Server.World; public class WorldServer { + #region Autofac Autowired private readonly GameStorage gameStorage; private readonly ChannelClientLookup channelClients; private readonly ServerTableMetadataStorage serverTableMetadata; @@ -25,6 +26,9 @@ public class WorldServer { private readonly GlobalPortalLookup globalPortalLookup; private readonly WorldBossLookup worldBossLookup; private readonly PlayerInfoLookup playerInfoLookup; + private ConstantsTable Constants => serverTableMetadata.ConstantsTable; + #endregion + private readonly Thread thread; private readonly Thread heartbeatThread; private readonly EventQueue scheduler; @@ -36,8 +40,6 @@ public class WorldServer { private readonly LoginClient login; - private ConstantsTable Constants => serverTableMetadata.ConstantsTable; - public WorldServer(GameStorage gameStorage, ChannelClientLookup channelClients, ServerTableMetadataStorage serverTableMetadata, GlobalPortalLookup globalPortalLookup, WorldBossLookup worldBossLookup, PlayerInfoLookup playerInfoLookup, LoginClient login, ItemMetadataStorage itemMetadata) { this.gameStorage = gameStorage; this.channelClients = channelClients; From da59e2906fad3f0c292f187b81fdad32966f3c51 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Thu, 5 Mar 2026 14:52:28 -0600 Subject: [PATCH 19/26] Correct NpcLastSight* constant values after adding them back from feedback. --- Maple2.Model/Metadata/Constants.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Maple2.Model/Metadata/Constants.cs b/Maple2.Model/Metadata/Constants.cs index 881d9d210..615e751b8 100644 --- a/Maple2.Model/Metadata/Constants.cs +++ b/Maple2.Model/Metadata/Constants.cs @@ -206,9 +206,9 @@ public static class Constant { // TODO: Remove once NpcMetadataDistance handles these at runtime, since they are now in DB and parsed through file ingest. #region Server table/constants.xml - public static readonly float NpcLastSightRadius = 0f; - public static readonly float NpcLastSightHeightUp = 0f; - public static readonly float NpcLastSightHeightDown = 0f; + public const float NpcLastSightRadius = 1800; + public const float NpcLastSightHeightUp = 525; + public const float NpcLastSightHeightDown = 225; #endregion } From fbb0b5c67e0e318d7bd0d00275577a22aa2c46af Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Fri, 6 Mar 2026 13:36:43 -0600 Subject: [PATCH 20/26] Update per Zin's feedback round 3 --- Maple2.Server.Game/Manager/ConfigManager.cs | 5 ++--- Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs | 6 +++--- Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs | 8 ++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Maple2.Server.Game/Manager/ConfigManager.cs b/Maple2.Server.Game/Manager/ConfigManager.cs index 56e460cac..a1ff26efe 100644 --- a/Maple2.Server.Game/Manager/ConfigManager.cs +++ b/Maple2.Server.Game/Manager/ConfigManager.cs @@ -102,16 +102,15 @@ public ConfigManager(GameStorage.Request db, GameSession session) { skillPoints = load.SkillPoint ?? new SkillPoint(); ExplorationProgress = load.ExplorationProgress; - statLimits = new Dictionary() { + statAttributes = new StatAttributes(new Dictionary() { { "StatPointLimit_str", Constants.StatPointLimit_str }, { "StatPointLimit_dex", Constants.StatPointLimit_dex }, { "StatPointLimit_int", Constants.StatPointLimit_int }, { "StatPointLimit_luk", Constants.StatPointLimit_luk }, { "StatPointLimit_hp", Constants.StatPointLimit_hp }, { "StatPointLimit_cap", Constants.StatPointLimit_cap } - }; + }); - statAttributes = new StatAttributes(statLimits); if (load.StatPoints != null) { foreach ((AttributePointSource source, int amount) in load.StatPoints) { if (source == AttributePointSource.Prestige) { diff --git a/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs b/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs index 776a1f7c4..3147c72a6 100644 --- a/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs @@ -39,7 +39,7 @@ public override void Handle(GameSession session, IByteReader packet) { HandleUnstage(session, packet); return; case Command.Commit: - HandleCommit(session, packet, Constants); + HandleCommit(session, packet); return; } } @@ -77,7 +77,7 @@ private static void HandleUnstage(GameSession session, IByteReader packet) { } } - private static void HandleCommit(GameSession session, IByteReader packet, ConstantsTable constants) { + private void HandleCommit(GameSession session, IByteReader packet) { bool unlock = packet.ReadBool(); // false - lock|true - unlock lock (session.Item) { @@ -94,7 +94,7 @@ private static void HandleCommit(GameSession session, IByteReader packet, Consta if (unlock && item.IsLocked) { item.IsLocked = false; - item.UnlockTime = DateTimeOffset.UtcNow.AddSeconds(constants.ItemUnLockTime).ToUnixTimeSeconds(); + item.UnlockTime = DateTimeOffset.UtcNow.AddSeconds(Constants.ItemUnLockTime).ToUnixTimeSeconds(); updatedItems.Add(item); } else if (!unlock && !item.IsLocked) { item.IsLocked = true; diff --git a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs index deb044282..89e785fad 100644 --- a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs @@ -39,7 +39,7 @@ public override void Handle(GameSession session, IByteReader packet) { HandleLoad(session, Constants); return; case Command.Create: - HandleCreate(session, packet, Constants); + HandleCreate(session, packet); return; case Command.Cancel: HandleCancel(session, packet); @@ -62,11 +62,11 @@ private static void HandleLoad(GameSession session, ConstantsTable constants) { session.Send(MesoMarketPacket.MyListings(myListings)); } - private static void HandleCreate(GameSession session, IByteReader packet, ConstantsTable constants) { + private void HandleCreate(GameSession session, IByteReader packet) { long amount = packet.ReadLong(); long price = packet.ReadLong(); - if (amount != constants.MesoMarketBasePrice) { + if (amount != Constants.MesoMarketBasePrice) { session.Send(MesoMarketPacket.Error(s_mesoMarket_error_invalidSaleMoney)); return; } @@ -103,7 +103,7 @@ private static void HandleCreate(GameSession session, IByteReader packet, Consta } session.Player.Value.Account.MesoMarketListed++; - session.Currency.Meso -= constants.MesoMarketBasePrice; + session.Currency.Meso -= Constants.MesoMarketBasePrice; session.Send(MesoMarketPacket.Create(listing)); session.Send(MesoMarketPacket.Quota(session.Player.Value.Account.MesoMarketListed, session.Player.Value.Account.MesoMarketPurchased)); } From 0b3b2c63a13648a3332f73940fd8d77eee3fab95 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Fri, 6 Mar 2026 13:40:34 -0600 Subject: [PATCH 21/26] Revert removal of statLimits from ConfigManager, it is used in two places other than just the initialization of StatAttributes. --- Maple2.Server.Game/Manager/ConfigManager.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Maple2.Server.Game/Manager/ConfigManager.cs b/Maple2.Server.Game/Manager/ConfigManager.cs index a1ff26efe..56e460cac 100644 --- a/Maple2.Server.Game/Manager/ConfigManager.cs +++ b/Maple2.Server.Game/Manager/ConfigManager.cs @@ -102,15 +102,16 @@ public ConfigManager(GameStorage.Request db, GameSession session) { skillPoints = load.SkillPoint ?? new SkillPoint(); ExplorationProgress = load.ExplorationProgress; - statAttributes = new StatAttributes(new Dictionary() { + statLimits = new Dictionary() { { "StatPointLimit_str", Constants.StatPointLimit_str }, { "StatPointLimit_dex", Constants.StatPointLimit_dex }, { "StatPointLimit_int", Constants.StatPointLimit_int }, { "StatPointLimit_luk", Constants.StatPointLimit_luk }, { "StatPointLimit_hp", Constants.StatPointLimit_hp }, { "StatPointLimit_cap", Constants.StatPointLimit_cap } - }); + }; + statAttributes = new StatAttributes(statLimits); if (load.StatPoints != null) { foreach ((AttributePointSource source, int amount) in load.StatPoints) { if (source == AttributePointSource.Prestige) { From 3f1a87c19ee745780777d6f3355529ae6765093b Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Fri, 6 Mar 2026 14:04:18 -0600 Subject: [PATCH 22/26] Remove the last unneccessary ConstantsTable parameter and fix some odd line breaks per Tadeucci's feedback --- Maple2.Server.Game/Manager/ExperienceManager.cs | 3 +-- .../Manager/Field/FieldManager/FieldManager.State.cs | 6 ++---- .../MovementStateTasks/MovementState.CleanupTask.cs | 3 +-- Maple2.Server.Game/Model/Field/Tombstone.cs | 3 +-- Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs | 2 +- Maple2.Server.Game/PacketHandlers/PartyHandler.cs | 4 ++-- Maple2.Server.Game/PacketHandlers/QuestHandler.cs | 10 +++++----- 7 files changed, 13 insertions(+), 18 deletions(-) diff --git a/Maple2.Server.Game/Manager/ExperienceManager.cs b/Maple2.Server.Game/Manager/ExperienceManager.cs index 0cca2aa36..75b01c3a8 100644 --- a/Maple2.Server.Game/Manager/ExperienceManager.cs +++ b/Maple2.Server.Game/Manager/ExperienceManager.cs @@ -218,8 +218,7 @@ private void AddPrestigeExp(ExpType expType) { return; } - if (PrestigeCurrentExp - PrestigeExp + (PrestigeLevelsGained * Constants.AdventureLevelLvUpExp) >= - Constants.AdventureLevelLvUpExp) { + if (PrestigeCurrentExp - PrestigeExp + (PrestigeLevelsGained * Constants.AdventureLevelLvUpExp) >= Constants.AdventureLevelLvUpExp) { amount = (long) (amount * Constants.AdventureLevelFactor); } diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs index d6f90d700..a09ea75b2 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs @@ -143,8 +143,7 @@ public FieldPlayer SpawnPlayer(GameSession session, Player player, int portalId AnimationMetadata? animation = NpcMetadata.GetAnimation(npc.Model.Name); string aiPath = disableAi ? string.Empty : npc.AiPath; - var fieldNpc = new FieldNpc(this, NextLocalId(), agent, new Npc(npc, animation), aiPath, - patrolDataUUID: spawnPointNpc?.PatrolData, spawnAnimation: spawnAnimation) { + var fieldNpc = new FieldNpc(this, NextLocalId(), agent, new Npc(npc, animation), aiPath, patrolDataUUID: spawnPointNpc?.PatrolData, spawnAnimation: spawnAnimation) { Owner = owner, Position = spawnPosition, Rotation = rotation, @@ -182,8 +181,7 @@ public FieldPlayer SpawnPlayer(GameSession session, Player player, int portalId int objectId = player != null ? NextGlobalId() : NextLocalId(); AnimationMetadata? animation = NpcMetadata.GetAnimation(npc.Model.Name); - var fieldPet = new FieldPet(this, objectId, agent, new Npc(npc, animation), - pet, petMetadata, Constant.PetFieldAiPath, player) { + var fieldPet = new FieldPet(this, objectId, agent, new Npc(npc, animation), pet, petMetadata, Constant.PetFieldAiPath, player) { Owner = owner, Position = position, Rotation = rotation, diff --git a/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs b/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs index cef66f6c0..6c29f60c8 100644 --- a/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs +++ b/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs @@ -41,8 +41,7 @@ protected override void TaskResumed() { return; } - float maxDistance = Constants.TalkableDistance * - Constants.TalkableDistance; + float maxDistance = Constants.TalkableDistance * Constants.TalkableDistance; // find nearest npc FieldNpc? closestNpc = player.Field.Npcs.Values diff --git a/Maple2.Server.Game/Model/Field/Tombstone.cs b/Maple2.Server.Game/Model/Field/Tombstone.cs index e39eba637..5f09e481c 100644 --- a/Maple2.Server.Game/Model/Field/Tombstone.cs +++ b/Maple2.Server.Game/Model/Field/Tombstone.cs @@ -33,8 +33,7 @@ public byte HitsRemaining { public Tombstone(FieldPlayer owner, int totalDeaths) { Owner = owner; - TotalHitCount = (byte) Math.Min(totalDeaths * Constants.hitPerDeadCount, - Constants.hitPerDeadCount * Constants.maxDeadCount); + TotalHitCount = (byte) Math.Min(totalDeaths * Constants.hitPerDeadCount, Constants.hitPerDeadCount * Constants.maxDeadCount); hitsRemaining = TotalHitCount; } public void WriteTo(IByteWriter writer) { diff --git a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs index 89e785fad..139c5ce12 100644 --- a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs @@ -53,7 +53,7 @@ public override void Handle(GameSession session, IByteReader packet) { } } - private static void HandleLoad(GameSession session, ConstantsTable constants) { + private static void HandleLoad(GameSession session) { session.Send(MesoMarketPacket.Load(AVERAGE_PRICE)); session.Send(MesoMarketPacket.Quota(session.Player.Value.Account.MesoMarketListed, session.Player.Value.Account.MesoMarketPurchased)); diff --git a/Maple2.Server.Game/PacketHandlers/PartyHandler.cs b/Maple2.Server.Game/PacketHandlers/PartyHandler.cs index 7b80e18f9..78c57561c 100644 --- a/Maple2.Server.Game/PacketHandlers/PartyHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/PartyHandler.cs @@ -287,8 +287,8 @@ private void HandleVoteKick(GameSession session, IByteReader packet) { return; } - if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(Constants.PartyVoteReadyDurationSeconds) - > DateTime.Now && session.Party.Party.Vote != null) { + if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(Constants.PartyVoteReadyDurationSeconds) > + DateTime.Now && session.Party.Party.Vote != null) { session.Send(PartyPacket.Error(PartyError.s_party_err_already_vote)); return; } diff --git a/Maple2.Server.Game/PacketHandlers/QuestHandler.cs b/Maple2.Server.Game/PacketHandlers/QuestHandler.cs index 5c59c0fea..f39dcf765 100644 --- a/Maple2.Server.Game/PacketHandlers/QuestHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/QuestHandler.cs @@ -69,7 +69,7 @@ public override void Handle(GameSession session, IByteReader packet) { HandleGoToDungeon(session, packet); break; case Command.SkyFortress: - HandleSkyFortressTeleport(session, Constants); + HandleSkyFortressTeleport(session); break; case Command.MapleGuide: HandleMapleGuide(session, packet); @@ -267,13 +267,13 @@ private static void HandleCompleteFieldMission(GameSession session, IByteReader session.Quest.CompleteFieldMission(mission); } - private static void HandleSkyFortressTeleport(GameSession session, ConstantsTable constants) { - if (!session.Quest.TryGetQuest(constants.FameContentsRequireQuestID, out Quest? quest) || quest.State != QuestState.Completed) { + private void HandleSkyFortressTeleport(GameSession session) { + if (!session.Quest.TryGetQuest(Constants.FameContentsRequireQuestID, out Quest? quest) || quest.State != QuestState.Completed) { return; } - session.Send(session.PrepareField(constants.FameContentsSkyFortressGotoMapID, - constants.FameContentsSkyFortressGotoPortalID) + session.Send(session.PrepareField(Constants.FameContentsSkyFortressGotoMapID, + Constants.FameContentsSkyFortressGotoPortalID) ? FieldEnterPacket.Request(session.Player) : FieldEnterPacket.Error(MigrationError.s_move_err_default)); } From efcb5ed709fcce2c775b6275d6ea4912cc2d7862 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Fri, 6 Mar 2026 14:17:02 -0600 Subject: [PATCH 23/26] Fix mistake on unncessary ConstantsTable parameter removal --- Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs index 139c5ce12..c41840d88 100644 --- a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs @@ -36,7 +36,7 @@ public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { case Command.Load: - HandleLoad(session, Constants); + HandleLoad(session); return; case Command.Create: HandleCreate(session, packet); From 377eed0584b6b998e4396e24235ab5dd56738360 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Fri, 6 Mar 2026 14:23:00 -0600 Subject: [PATCH 24/26] Run dotnet format --- Maple2.File.Ingest/Utils/GenericHelper.cs | 2 +- Maple2.Server.Game/Commands/PlayerCommand.cs | 2 +- .../Manager/Field/FieldManager/FieldManager.State.cs | 2 +- Maple2.Server.Game/PacketHandlers/ClubHandler.cs | 2 +- Maple2.Server.Game/PacketHandlers/GuildHandler.cs | 2 +- Maple2.Server.World/Containers/PartyLookup.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Maple2.File.Ingest/Utils/GenericHelper.cs b/Maple2.File.Ingest/Utils/GenericHelper.cs index a01f96150..0cbef75fb 100644 --- a/Maple2.File.Ingest/Utils/GenericHelper.cs +++ b/Maple2.File.Ingest/Utils/GenericHelper.cs @@ -84,7 +84,7 @@ private static bool TryParseObject(Type? elementType, object? input, out object? null, simpleArgs, null); if (method != null) { object[] args = { inputString, null! }; - bool success = (bool)method.Invoke(null, args)!; + bool success = (bool) method.Invoke(null, args)!; result = args[1]; return success; } diff --git a/Maple2.Server.Game/Commands/PlayerCommand.cs b/Maple2.Server.Game/Commands/PlayerCommand.cs index b11135991..bf4577f40 100644 --- a/Maple2.Server.Game/Commands/PlayerCommand.cs +++ b/Maple2.Server.Game/Commands/PlayerCommand.cs @@ -203,7 +203,7 @@ public PrestigeCommand(GameSession session) : base("prestige", "Sets prestige le private void Handle(InvocationContext ctx, int level) { try { - if (level < 1 || level > Constants.AdventureLevelLimit) { + if (level < 1 || level > Constants.AdventureLevelLimit) { ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {Constants.AdventureLevelLimit}."); return; } diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs index a09ea75b2..22e3fcf0c 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs @@ -721,7 +721,7 @@ public void RemoveSkillByTriggerId(int triggerId) { private void AddCubeSkill(SkillMetadata metadata, in Vector3 position, in Vector3 rotation = default) { Vector3 adjustedPosition = position; adjustedPosition.Z += FieldAccelerationStructure.BLOCK_SIZE; - var fieldSkill = new FieldSkill(this, NextLocalId(), FieldActor, metadata, (int)Constants.GlobalCubeSkillIntervalTime.TotalMilliseconds, adjustedPosition) { + var fieldSkill = new FieldSkill(this, NextLocalId(), FieldActor, metadata, (int) Constants.GlobalCubeSkillIntervalTime.TotalMilliseconds, adjustedPosition) { Position = adjustedPosition, Rotation = rotation, Source = SkillSource.Cube, diff --git a/Maple2.Server.Game/PacketHandlers/ClubHandler.cs b/Maple2.Server.Game/PacketHandlers/ClubHandler.cs index 5a866e8d7..a18d6f710 100644 --- a/Maple2.Server.Game/PacketHandlers/ClubHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/ClubHandler.cs @@ -34,7 +34,7 @@ private enum Command : byte { // ReSharper disable MemberCanBePrivate.Global public required WorldClient World { private get; init; } public required BanWordStorage BanWordStorage { private get; init; } - public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion diff --git a/Maple2.Server.Game/PacketHandlers/GuildHandler.cs b/Maple2.Server.Game/PacketHandlers/GuildHandler.cs index 18c18db35..da2722e51 100644 --- a/Maple2.Server.Game/PacketHandlers/GuildHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/GuildHandler.cs @@ -65,7 +65,7 @@ private enum Command : byte { public required WorldClient World { private get; init; } public required TableMetadataStorage TableMetadata { private get; init; } public required BanWordStorage BanWordStorage { private get; init; } - public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion diff --git a/Maple2.Server.World/Containers/PartyLookup.cs b/Maple2.Server.World/Containers/PartyLookup.cs index 0220242b2..a3249b955 100644 --- a/Maple2.Server.World/Containers/PartyLookup.cs +++ b/Maple2.Server.World/Containers/PartyLookup.cs @@ -65,7 +65,7 @@ public PartyError Create(long leaderId, out int partyId) { var manager = new PartyManager(party) { ChannelClients = channelClients, PartyLookup = this, - ServerTableMetadata = serverTableMetadata + ServerTableMetadata = serverTableMetadata }; if (!parties.TryAdd(partyId, manager)) { From c86521a9749f5619b8429f3b2b7ba5c665b05e8b Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Fri, 6 Mar 2026 14:40:27 -0600 Subject: [PATCH 25/26] Fix dotnet format fail --- Maple2.File.Ingest/Utils/GenericHelper.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Maple2.File.Ingest/Utils/GenericHelper.cs b/Maple2.File.Ingest/Utils/GenericHelper.cs index 0cbef75fb..93e3be358 100644 --- a/Maple2.File.Ingest/Utils/GenericHelper.cs +++ b/Maple2.File.Ingest/Utils/GenericHelper.cs @@ -3,6 +3,7 @@ using System.Reflection; namespace Maple2.File.Ingest.Utils; + public static class GenericHelper { public static void SetValue(PropertyInfo prop, object? obj, object? value) { if (obj == null && value == null || value == null) return; From 6eb2b5c261dc1d2beab15cec83176ee308d06922 Mon Sep 17 00:00:00 2001 From: mfranca915 Date: Mon, 9 Mar 2026 13:51:24 -0500 Subject: [PATCH 26/26] Make adjustments based off coderabbitai suggestions. --- Maple2.File.Ingest/Utils/GenericHelper.cs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Maple2.File.Ingest/Utils/GenericHelper.cs b/Maple2.File.Ingest/Utils/GenericHelper.cs index 93e3be358..23446cec8 100644 --- a/Maple2.File.Ingest/Utils/GenericHelper.cs +++ b/Maple2.File.Ingest/Utils/GenericHelper.cs @@ -31,19 +31,25 @@ public static void SetValue(PropertyInfo prop, object? obj, object? value) { string[] segments = ((string) value).Split(','); Array destinationArray = Array.CreateInstance(elementType, segments.Length); for (int i = 0; i < segments.Length; i++) { - TryParseObject(elementType, segments[i].Trim(), out object? parseResult); - destinationArray.SetValue(parseResult ?? default, i); + if (TryParseObject(elementType, segments[i].Trim(), out object? parseResult)) { + destinationArray.SetValue(parseResult ?? default, i); + }else { + destinationArray.SetValue(elementType.IsValueType ? Activator.CreateInstance(elementType) : null, i); + } } value = destinationArray; } // Handle Vector3 type if (prop.PropertyType == typeof(Vector3)) { string[] parts = ((string) value).Split(','); - if (parts.Length != 3) return value; - float.TryParse(parts[0], CultureInfo.InvariantCulture, out float x); - float.TryParse(parts[1], CultureInfo.InvariantCulture, out float y); - float.TryParse(parts[2], CultureInfo.InvariantCulture, out float z); - value = new Vector3(x, y, z); + bool parseXSuccess = float.TryParse(parts[0], CultureInfo.InvariantCulture, out float x); + bool parseYSuccess = float.TryParse(parts[1], CultureInfo.InvariantCulture, out float y); + bool parseZSuccess = float.TryParse(parts[2], CultureInfo.InvariantCulture, out float z); + if (parts.Length != 3 || parseXSuccess && parseYSuccess && parseZSuccess) { + value = Vector3.Zero; + } else { + value = new Vector3(x, y, z); + } } return value; } @@ -78,7 +84,7 @@ private static bool TryParseObject(Type? elementType, object? input, out object? return success; } - // Fallback without CulturueInfo provided, in case the type does not have a CultureInfo overload. + // Fallback without CultureInfo provided, in case the type does not have a CultureInfo overload. Type[] simpleArgs = { typeof(string), elementType.MakeByRefType() }; method = elementType.GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static,