-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
269 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
namespace Lib9c.Tests.Action | ||
{ | ||
using System.Linq; | ||
using Lib9c.Tests.Util; | ||
using Libplanet.Action.State; | ||
using Libplanet.Crypto; | ||
using Libplanet.Mocks; | ||
using Nekoyume; | ||
using Nekoyume.Action; | ||
using Nekoyume.Model.Mail; | ||
using Nekoyume.Model.State; | ||
using Nekoyume.Module; | ||
using Serilog; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
public class ClaimPatrolRewardTest | ||
{ | ||
private readonly IWorld _initialState; | ||
private readonly TableSheets _tableSheets; | ||
|
||
public ClaimPatrolRewardTest(ITestOutputHelper outputHelper) | ||
{ | ||
Log.Logger = new LoggerConfiguration() | ||
.MinimumLevel.Verbose() | ||
.WriteTo.TestOutput(outputHelper) | ||
.CreateLogger(); | ||
|
||
_initialState = new World(MockUtil.MockModernWorldState); | ||
|
||
var sheets = TableSheetsImporter.ImportSheets(); | ||
foreach (var (key, value) in sheets) | ||
{ | ||
_initialState = _initialState | ||
.SetLegacyState(Addresses.TableSheet.Derive(key), value.Serialize()); | ||
} | ||
|
||
_tableSheets = new TableSheets(sheets); | ||
} | ||
|
||
[Fact] | ||
public void Execute() | ||
{ | ||
var privateKey = new PrivateKey(); | ||
var agentAddress = privateKey.Address; | ||
var row = _tableSheets.PatrolRewardSheet.Values.First(); | ||
var (state, avatar, _) = InitializeUtil.AddAvatar(_initialState, _tableSheets.GetAvatarSheets(), agentAddress); | ||
var avatarAddress = avatar.address; | ||
var action = new ClaimPatrolReward(avatar.address); | ||
|
||
var nextState = action.Execute(new ActionContext | ||
{ | ||
Signer = agentAddress, | ||
BlockIndex = 1L, | ||
PreviousState = state, | ||
RandomSeed = 0, | ||
}); | ||
|
||
var avatarState = nextState.GetAvatarState(avatarAddress); | ||
var itemSheet = _tableSheets.ItemSheet; | ||
var mail = Assert.IsType<PatrolRewardMail>(avatarState.mailBox.Single()); | ||
|
||
foreach (var reward in row.Rewards) | ||
{ | ||
var ticker = reward.Ticker; | ||
if (string.IsNullOrEmpty(ticker)) | ||
{ | ||
var itemId = reward.ItemId; | ||
var rowId = itemSheet[itemId].Id; | ||
Assert.True(avatarState.inventory.HasItem(rowId, reward.Count)); | ||
var item = mail.Items.First(i => i.id == itemId); | ||
Assert.Equal(item.count, reward.Count); | ||
} | ||
else | ||
{ | ||
var currency = Currencies.GetMinterlessCurrency(ticker); | ||
var recipient = Currencies.PickAddress(currency, agentAddress, avatarAddress); | ||
var fav = nextState.GetBalance(recipient, currency); | ||
Assert.Equal(currency * reward.Count, fav); | ||
Assert.Contains(fav, mail.FungibleAssetValues); | ||
} | ||
} | ||
|
||
Assert.Equal(1L, nextState.GetPatrolRewardClaimedBlockIndex(avatarAddress)); | ||
Assert.True(row.Interval > 1L); | ||
|
||
// Throw RequiredBlockIndex by reward interval | ||
Assert.Throws<RequiredBlockIndexException>(() => action.Execute(new ActionContext | ||
{ | ||
Signer = agentAddress, | ||
BlockIndex = 2L, | ||
PreviousState = nextState, | ||
RandomSeed = 0, | ||
})); | ||
} | ||
|
||
[Fact] | ||
public void Execute_Throw_InvalidAddressException() | ||
{ | ||
var signer = new PrivateKey().Address; | ||
var action = new ClaimPatrolReward(signer); | ||
|
||
Assert.Throws<InvalidAddressException>(() => action.Execute(new ActionContext | ||
{ | ||
Signer = signer, | ||
BlockIndex = 0, | ||
PreviousState = _initialState, | ||
})); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using Bencodex.Types; | ||
using Lib9c; | ||
using Libplanet.Action; | ||
using Libplanet.Action.State; | ||
using Libplanet.Crypto; | ||
using Libplanet.Types.Assets; | ||
using Nekoyume.Extensions; | ||
using Nekoyume.Helper; | ||
using Nekoyume.Model.Item; | ||
using Nekoyume.Model.Mail; | ||
using Nekoyume.Model.State; | ||
using Nekoyume.Module; | ||
using Nekoyume.TableData; | ||
using Nekoyume.TableData.Event; | ||
|
||
namespace Nekoyume.Action | ||
{ | ||
/// <summary> | ||
/// Claim patrol reward | ||
/// </summary> | ||
[Serializable] | ||
[ActionType(TypeIdentifier)] | ||
public class ClaimPatrolReward : ActionBase | ||
{ | ||
public const string TypeIdentifier = "claim_patrol_reward"; | ||
public Address AvatarAddress; | ||
|
||
public ClaimPatrolReward() | ||
{ | ||
} | ||
|
||
public ClaimPatrolReward(Address avatarAddress) | ||
{ | ||
AvatarAddress = avatarAddress; | ||
} | ||
public override IWorld Execute(IActionContext context) | ||
{ | ||
GasTracer.UseGas(1); | ||
var signer = context.Signer; | ||
var states = context.PreviousState; | ||
if (!Addresses.CheckAvatarAddrIsContainedInAgent(signer, AvatarAddress)) | ||
{ | ||
throw new InvalidAddressException(); | ||
} | ||
|
||
// avatar | ||
var avatarState = states.GetAvatarState(AvatarAddress, true, false, false); | ||
var avatarLevel = avatarState.level; | ||
var inventory = avatarState.inventory; | ||
|
||
// sheets | ||
var sheets = states.GetSheets(containItemSheet: true, sheetTypes: new[] | ||
{ | ||
typeof(PatrolRewardSheet) | ||
}); | ||
var patrolRewardSheet = sheets.GetSheet<PatrolRewardSheet>(); | ||
var itemSheet = sheets.GetItemSheet(); | ||
|
||
// validate | ||
states.TryGetPatrolRewardClaimedBlockIndex(AvatarAddress, out var claimedBlockIndex); | ||
var row = patrolRewardSheet.FindByLevel(avatarLevel, context.BlockIndex); | ||
if (claimedBlockIndex > 0L && claimedBlockIndex + row.Interval > context.BlockIndex) | ||
{ | ||
throw new RequiredBlockIndexException(); | ||
} | ||
|
||
// mit rewards | ||
var random = context.GetRandom(); | ||
var favs = new List<FungibleAssetValue>(); | ||
var items = new List<(int id, int count)>(); | ||
foreach (var reward in row.Rewards) | ||
{ | ||
var ticker = reward.Ticker; | ||
if (string.IsNullOrEmpty(ticker)) | ||
{ | ||
var itemRow = itemSheet[reward.ItemId]; | ||
inventory.MintItem(itemRow, reward.Count, false, random); | ||
items.Add(new (reward.ItemId, reward.Count)); | ||
} | ||
else | ||
{ | ||
var currency = Currencies.GetMinterlessCurrency(ticker); | ||
var recipient = Currencies.PickAddress(currency, signer, AvatarAddress); | ||
var fav = currency * reward.Count; | ||
states = states.MintAsset(context, recipient, fav); | ||
favs.Add(fav); | ||
} | ||
} | ||
|
||
var mailBox = avatarState.mailBox; | ||
var mail = new PatrolRewardMail(context.BlockIndex, random.GenerateRandomGuid(), context.BlockIndex, favs, items); | ||
mailBox.Add(mail); | ||
mailBox.CleanUp(); | ||
avatarState.mailBox = mailBox; | ||
|
||
// set states | ||
states = states | ||
.SetAvatarState(AvatarAddress, avatarState, setAvatar: true, setInventory: true, setWorldInformation: false, setQuestList: false) | ||
.SetPatrolRewardClaimedBlockIndex(AvatarAddress, context.BlockIndex); | ||
return states; | ||
} | ||
|
||
public override IValue PlainValue => Dictionary.Empty | ||
.Add("type_id", TypeIdentifier) | ||
.Add("values", AvatarAddress.Serialize()); | ||
public override void LoadPlainValue(IValue plainValue) | ||
{ | ||
AvatarAddress = ((Dictionary)plainValue)["values"].ToAddress(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using Bencodex.Types; | ||
using Libplanet.Action.State; | ||
using Libplanet.Crypto; | ||
using Nekoyume.Action; | ||
|
||
namespace Nekoyume.Module | ||
{ | ||
public static class PatrolRewardModule | ||
{ | ||
public static long GetPatrolRewardClaimedBlockIndex(this IWorldState worldState, Address avatarAddress) | ||
{ | ||
var value = worldState.GetAccountState(Addresses.PatrolReward).GetState(avatarAddress); | ||
if (value is Integer integer) | ||
{ | ||
return integer; | ||
} | ||
|
||
throw new FailedLoadStateException(""); | ||
} | ||
|
||
public static bool TryGetPatrolRewardClaimedBlockIndex(this IWorldState worldState, Address avatarAddress, out long blockIndex) | ||
{ | ||
blockIndex = 0L; | ||
try | ||
{ | ||
var temp = GetPatrolRewardClaimedBlockIndex(worldState, avatarAddress); | ||
blockIndex = temp; | ||
return true; | ||
} | ||
catch (FailedLoadStateException) | ||
{ | ||
return false; | ||
} | ||
} | ||
|
||
public static IWorld SetPatrolRewardClaimedBlockIndex(this IWorld world, Address avatarAddress, long blockIndex) | ||
{ | ||
var account = world.GetAccount(Addresses.PatrolReward); | ||
account = account.SetState(avatarAddress, (Integer)blockIndex); | ||
return world.SetAccount(Addresses.PatrolReward, account); | ||
} | ||
} | ||
} |