Skip to content

Commit

Permalink
create ClaimOneTimeGift(action), OneTimeGiftSheet(sheet)
Browse files Browse the repository at this point in the history
  • Loading branch information
tyrosine1153 committed Oct 30, 2024
1 parent 8f11988 commit 655b8a4
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 0 deletions.
117 changes: 117 additions & 0 deletions Lib9c/Action/ClaimOneTimeGift.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Bencodex.Types;
using Libplanet.Action;
using Libplanet.Action.State;
using Libplanet.Crypto;
using Nekoyume.Extensions;
using Nekoyume.Model.Item;
using Nekoyume.Model.State;
using Nekoyume.Module;
using Nekoyume.TableData;
using static Lib9c.SerializeKeys;

namespace Nekoyume.Action
{
[ActionType(ActionTypeText)]
public class ClaimOneTimeGift : GameAction
{
private const string ActionTypeText = "claim_one_time_gift";

public Address AvatarAddress;

public static Address ClaimedGiftIdsAddress(Address avatarAddress) =>
avatarAddress.Derive("claimed_gift_ids");

public ClaimOneTimeGift(Address avatarAddress)
{
AvatarAddress = avatarAddress;
}

public ClaimOneTimeGift()
{
}

protected override IImmutableDictionary<string, IValue> PlainValueInternal =>
ImmutableDictionary<string, IValue>.Empty
.Add(AvatarAddressKey, AvatarAddress.Serialize());

protected override void LoadPlainValueInternal(IImmutableDictionary<string, IValue> plainValue)
{
AvatarAddress = plainValue[AvatarAddressKey].ToAddress();
}

public override IWorld Execute(IActionContext context)
{
context.UseGas(1);
var states = context.PreviousState;
var random = context.GetRandom();
var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress);

var avatarState = states.GetAvatarState(AvatarAddress,
getWorldInformation: false,
getQuestList: false);
if (avatarState is null)
{
throw new FailedLoadStateException(
ActionTypeText,
addressesHex,
typeof(AvatarState),
AvatarAddress);
}

var sheetTypes = new []
{
typeof(OneTimeGiftSheet),
};
var sheets = states.GetSheets(
containItemSheet: true,
sheetTypes: sheetTypes);

var oneTimeGiftSheet = sheets.GetSheet<OneTimeGiftSheet>();
if (!oneTimeGiftSheet.TryFindRowByBlockIndex(context.BlockIndex, out var giftRow))
{
throw new ClaimableGiftDoesNotExistException(
$"[{addressesHex}] Claimable gift does not exist at block index: {context.BlockIndex}"
);
}

var claimedGiftIdsAddress = ClaimedGiftIdsAddress(AvatarAddress);
var claimedGiftIds = states.TryGetLegacyState(claimedGiftIdsAddress, out List rawIds)
? rawIds.ToList(StateExtensions.ToInteger)
: new List<int>();
if (claimedGiftIds.Contains(giftRow.Id))
{
throw new AlreadyClaimedGiftException(
$"[{addressesHex}] Already claimed gift: {giftRow.Id}"
);
}

var itemSheet = sheets.GetItemSheet();
foreach (var (itemId, count) in giftRow.Rewards)
{
var item = ItemFactory.CreateItem(itemSheet[itemId], random);
if (item is INonFungibleItem)
{
foreach (var _ in Enumerable.Range(0, count))
{
avatarState.inventory.AddItem(item);
}
}
else
{
avatarState.inventory.AddItem(item, count);
}
}

claimedGiftIds.Add(giftRow.Id);

return states
.SetLegacyState(claimedGiftIdsAddress, claimedGiftIds.Aggregate(List.Empty,
(current, giftId) => current.Add(giftId.Serialize())))
.SetAvatarState(AvatarAddress, avatarState, setWorldInformation: false, setQuestList: false);
}
}
}
37 changes: 37 additions & 0 deletions Lib9c/Action/ClaimOneTimeGiftException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Runtime.Serialization;

namespace Nekoyume.Action
{
[Serializable]
public class AlreadyClaimedGiftException : Exception
{
public AlreadyClaimedGiftException()
{
}

public AlreadyClaimedGiftException(string msg) : base(msg)
{
}

public AlreadyClaimedGiftException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}

[Serializable]
public class ClaimableGiftDoesNotExistException : Exception
{
public ClaimableGiftDoesNotExistException()
{
}

public ClaimableGiftDoesNotExistException(string msg) : base(msg)
{
}

public ClaimableGiftDoesNotExistException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}
48 changes: 48 additions & 0 deletions Lib9c/TableData/OneTimeGiftSheet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Collections.Generic;
using System.Linq;
using static Nekoyume.TableData.TableExtensions;

namespace Nekoyume.TableData
{
public class OneTimeGiftSheet : Sheet<int, OneTimeGiftSheet.Row>
{
public class Row : SheetRow<int>
{
public override int Key => Id;
public int Id;
public long StartedBlockIndex;
public long EndedBlockIndex;
public List<(int itemId, int Count)> Rewards;

public override void Set(IReadOnlyList<string> fields)
{
Id = ParseInt(fields[0]);
StartedBlockIndex = ParseLong(fields[1]);
EndedBlockIndex = ParseLong(fields[2]);

Rewards = new List<(int, int)>();
for (int i = 0; i < 5; i++)
{
var offset = i * 2;
if (!TryParseInt(fields[3 + offset], out var materialId) || materialId == 0 ||
!TryParseInt(fields[4 + offset], out var count) || count == 0)
{
continue;
}

Rewards.Add((materialId, count));
}
}
}

public OneTimeGiftSheet() : base(nameof(OneTimeGiftSheet))
{
}

public bool TryFindRowByBlockIndex(long blockIndex, out Row row)
{
row = OrderedList.FirstOrDefault(r => r.StartedBlockIndex <= blockIndex && blockIndex <= r.EndedBlockIndex);
return row != null;
}
}
}

0 comments on commit 655b8a4

Please sign in to comment.