From b6b473d265841911093c8b61a174d02e1d59ca9b Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 29 Aug 2024 14:33:36 +0900 Subject: [PATCH 1/3] Throw exception when negative value comes in --- Lib9c/Action/HackAndSlashSweep.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Lib9c/Action/HackAndSlashSweep.cs b/Lib9c/Action/HackAndSlashSweep.cs index 36df8c89e8..19fe8c93f4 100644 --- a/Lib9c/Action/HackAndSlashSweep.cs +++ b/Lib9c/Action/HackAndSlashSweep.cs @@ -18,7 +18,6 @@ using Nekoyume.TableData; using Nekoyume.TableData.Rune; using Serilog; -using static Lib9c.SerializeKeys; namespace Nekoyume.Action { @@ -91,6 +90,13 @@ public override IWorld Execute(IActionContext context) $"apStoneCount : {apStoneCount} > UsableApStoneCount : {UsableApStoneCount}"); } + if (apStoneCount < 0 || actionPoint < 0) + { + throw new ArgumentOutOfRangeException( + $"{addressesHex} Aborted as the player give negative value ({actionPoint} AP & {apStoneCount} potions)" + ); + } + states.ValidateWorldId(avatarAddress, worldId); if (!states.TryGetAvatarState( From 5aa7a6aa23d47aecdcf498a588979800d63e9f3f Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 29 Aug 2024 14:38:05 +0900 Subject: [PATCH 2/3] Format codes --- Lib9c/Action/HackAndSlashSweep.cs | 39 ++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/Lib9c/Action/HackAndSlashSweep.cs b/Lib9c/Action/HackAndSlashSweep.cs index 19fe8c93f4..3b474acfe9 100644 --- a/Lib9c/Action/HackAndSlashSweep.cs +++ b/Lib9c/Action/HackAndSlashSweep.cs @@ -41,8 +41,10 @@ public class HackAndSlashSweep : GameAction, IHackAndSlashSweepV3 IEnumerable IHackAndSlashSweepV3.Costumes => costumes; IEnumerable IHackAndSlashSweepV3.Equipments => equipments; + IEnumerable IHackAndSlashSweepV3.RuneSlotInfos => runeInfos.Select(x => x.Serialize()); + Address IHackAndSlashSweepV3.AvatarAddress => avatarAddress; int IHackAndSlashSweepV3.ApStoneCount => apStoneCount; int IHackAndSlashSweepV3.ActionPoint => actionPoint; @@ -54,7 +56,8 @@ public class HackAndSlashSweep : GameAction, IHackAndSlashSweepV3 { ["costumes"] = new List(costumes.OrderBy(i => i).Select(e => e.Serialize())), ["equipments"] = new List(equipments.OrderBy(i => i).Select(e => e.Serialize())), - ["runeInfos"] = runeInfos.OrderBy(x => x.SlotIndex).Select(x=> x.Serialize()).Serialize(), + ["runeInfos"] = runeInfos.OrderBy(x => x.SlotIndex) + .Select(x => x.Serialize()).Serialize(), ["avatarAddress"] = avatarAddress.Serialize(), ["apStoneCount"] = apStoneCount.Serialize(), ["actionPoint"] = actionPoint.Serialize(), @@ -108,7 +111,9 @@ public override IWorld Execute(IActionContext context) $"{addressesHex}Aborted as the avatar state of the signer was failed to load."); } - var collectionExist = states.TryGetCollectionState(avatarAddress, out var collectionState) && collectionState.Ids.Any(); + var collectionExist = + states.TryGetCollectionState(avatarAddress, out var collectionState) && + collectionState.Ids.Any(); var sheetTypes = new List { typeof(WorldSheet), @@ -132,6 +137,7 @@ public override IWorld Execute(IActionContext context) { sheetTypes.Add(typeof(CollectionSheet)); } + var sheets = states.GetSheets( sheetTypes: sheetTypes); @@ -212,19 +218,23 @@ public override IWorld Execute(IActionContext context) } // update rune slot - var runeSlotStateAddress = RuneSlotState.DeriveAddress(avatarAddress, BattleType.Adventure); - var runeSlotState = states.TryGetLegacyState(runeSlotStateAddress, out List rawRuneSlotState) - ? new RuneSlotState(rawRuneSlotState) - : new RuneSlotState(BattleType.Adventure); + var runeSlotStateAddress = + RuneSlotState.DeriveAddress(avatarAddress, BattleType.Adventure); + var runeSlotState = + states.TryGetLegacyState(runeSlotStateAddress, out List rawRuneSlotState) + ? new RuneSlotState(rawRuneSlotState) + : new RuneSlotState(BattleType.Adventure); var runeListSheet = sheets.GetSheet(); runeSlotState.UpdateSlot(runeInfos, runeListSheet); states = states.SetLegacyState(runeSlotStateAddress, runeSlotState.Serialize()); // update item slot - var itemSlotStateAddress = ItemSlotState.DeriveAddress(avatarAddress, BattleType.Adventure); - var itemSlotState = states.TryGetLegacyState(itemSlotStateAddress, out List rawItemSlotState) - ? new ItemSlotState(rawItemSlotState) - : new ItemSlotState(BattleType.Adventure); + var itemSlotStateAddress = + ItemSlotState.DeriveAddress(avatarAddress, BattleType.Adventure); + var itemSlotState = + states.TryGetLegacyState(itemSlotStateAddress, out List rawItemSlotState) + ? new ItemSlotState(rawItemSlotState) + : new ItemSlotState(BattleType.Adventure); itemSlotState.UpdateEquipment(equipments); itemSlotState.UpdateCostumes(costumes); states = states.SetLegacyState(itemSlotStateAddress, itemSlotState.Serialize()); @@ -244,6 +254,7 @@ public override IWorld Execute(IActionContext context) equippedRune.Add(runeState); } } + var runeOptionSheet = sheets.GetSheet(); var runeOptions = new List(); foreach (var runeState in equippedRune) @@ -360,9 +371,11 @@ public override IWorld Execute(IActionContext context) avatarState.UpdateExp(level, exp); var ended = DateTimeOffset.UtcNow; - Log.Debug("{AddressesHex}HackAndSlashSweep Total Executed Time: {Elapsed}", addressesHex, ended - started); - return states - .SetAvatarState(avatarAddress, avatarState); + Log.Debug( + "{AddressesHex}HackAndSlashSweep Total Executed Time: {Elapsed}", + addressesHex, ended - started + ); + return states.SetAvatarState(avatarAddress, avatarState); } public static List GetRewardItems(IRandom random, From f7f14b3b87ce673f8b2f320450e3e67b4d4ab60e Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 29 Aug 2024 14:54:54 +0900 Subject: [PATCH 3/3] Add tests --- .Lib9c.Tests/Action/HackAndSlashSweepTest.cs | 59 ++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/.Lib9c.Tests/Action/HackAndSlashSweepTest.cs b/.Lib9c.Tests/Action/HackAndSlashSweepTest.cs index 6474c36db2..e476a7cfda 100644 --- a/.Lib9c.Tests/Action/HackAndSlashSweepTest.cs +++ b/.Lib9c.Tests/Action/HackAndSlashSweepTest.cs @@ -705,5 +705,64 @@ public void ExecuteDuplicatedException(int slotIndex, int runeId, int slotIndex2 throw new SheetRowNotFoundException(nameof(StageSheet), stageId); } } + + [Theory] + [InlineData(0, -1)] + [InlineData(0, int.MinValue + 1)] + [InlineData(-1, 0)] + [InlineData(int.MinValue + 1, 0)] + public void Execute_ArgumentOutOfRangeException(int ap, int apPotion) + { + var avatarState = new AvatarState( + _avatarAddress, + _agentAddress, + 0, + _initialState.GetAvatarSheets(), + _rankingMapAddress) + { + worldInformation = + new WorldInformation(0, _initialState.GetSheet(), 25), + level = 400, + }; + + IWorld state = _initialState.SetAvatarState(_avatarAddress, avatarState) + .SetActionPoint(_avatarAddress, 0); + var actionPoint = _initialState.GetActionPoint(_avatarAddress); + + var stageSheet = _initialState.GetSheet(); + var (expectedLevel, expectedExp) = (0, 0L); + if (stageSheet.TryGetValue(2, out var stageRow)) + { + var itemPlayCount = + DailyReward.ActionPointMax / stageRow.CostAP * 1; + var apPlayCount = actionPoint / stageRow.CostAP; + var playCount = apPlayCount + itemPlayCount; + (expectedLevel, expectedExp) = avatarState.GetLevelAndExp( + _tableSheets.CharacterLevelSheet, + 2, + (int)playCount); + + var (equipments, costumes) = GetDummyItems(avatarState); + var action = new HackAndSlashSweep + { + runeInfos = new List(), + costumes = costumes, + equipments = equipments, + avatarAddress = _avatarAddress, + actionPoint = ap, + apStoneCount = apPotion, + worldId = 1, + stageId = 2, + }; + + Assert.Throws(() => + action.Execute(new ActionContext() + { + PreviousState = state, + Signer = _agentAddress, + RandomSeed = 0, + })); + } + } } }