Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ipdae committed Nov 28, 2023
1 parent d6d629e commit 9326922
Show file tree
Hide file tree
Showing 4 changed files with 473 additions and 1 deletion.
259 changes: 259 additions & 0 deletions .Lib9c.Tests/Action/Summon/RuneSummonTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
namespace Lib9c.Tests.Action.Summon
{
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Lib9c.Tests.Fixtures.TableCSV.Summon;
using Libplanet.Action.State;
using Libplanet.Crypto;
using Libplanet.Types.Assets;
using Nekoyume;
using Nekoyume.Action;
using Nekoyume.Action.Exceptions;
using Nekoyume.Model.Item;
using Nekoyume.Model.State;
using Nekoyume.TableData.Summon;
using Xunit;
using static SerializeKeys;

public class RuneSummonTest
{
private readonly Address _agentAddress;
private readonly Address _avatarAddress;
private readonly AvatarState _avatarState;
private readonly Currency _currency;
private TableSheets _tableSheets;
private IAccount _initialState;

public RuneSummonTest()
{
var sheets = TableSheetsImporter.ImportSheets();
_tableSheets = new TableSheets(sheets);
var privateKey = new PrivateKey();
_agentAddress = privateKey.PublicKey.Address;
var agentState = new AgentState(_agentAddress);

_avatarAddress = _agentAddress.Derive("avatar");
_avatarState = new AvatarState(
_avatarAddress,
_agentAddress,
0,
_tableSheets.GetAvatarSheets(),
new GameConfigState(),
default
);

agentState.avatarAddresses.Add(0, _avatarAddress);

#pragma warning disable CS0618
// Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319
_currency = Currency.Legacy("NCG", 2, null);
#pragma warning restore CS0618
var gold = new GoldCurrencyState(_currency);

var context = new ActionContext();
_initialState = new Account(MockState.Empty)
.SetState(_agentAddress, agentState.Serialize())
.SetState(_avatarAddress, _avatarState.Serialize())
.SetState(GoldCurrencyState.Address, gold.Serialize())
.MintAsset(context, GoldCurrencyState.Address, gold.Currency * 100000000000)
.TransferAsset(
context,
Addresses.GoldCurrency,
_agentAddress,
gold.Currency * 1000
);

Assert.Equal(
gold.Currency * 99999999000,
_initialState.GetBalance(Addresses.GoldCurrency, gold.Currency)
);
Assert.Equal(
gold.Currency * 1000,
_initialState.GetBalance(_agentAddress, gold.Currency)
);

foreach (var (key, value) in sheets)
{
_initialState =
_initialState.SetState(Addresses.TableSheet.Derive(key), value.Serialize());
}
}

[Theory]
[InlineData(20001)]
[InlineData(20002)]
public void CumulativeRatio(int groupId)
{
var sheet = _tableSheets.SummonSheet;
var targetRow = sheet.OrderedList.First(r => r.GroupId == groupId);

for (var i = 1; i <= SummonSheet.Row.MaxRecipeCount; i++)
{
var sum = 0;
for (var j = 0; j < i; j++)
{
if (j < targetRow.Recipes.Count)
{
sum += targetRow.Recipes[j].Item2;
}
}

Assert.Equal(sum, targetRow.CumulativeRatio(i));
}
}

[Theory]
// success first group
[InlineData(20001, 1, 800201, 1, 1, new[] { 10610000 }, null)]
[InlineData(20001, 2, 800201, 2, 54, new[] { 10620000, 10630000 }, null)]
// success second group
[InlineData(20002, 1, 600201, 1, 1, new[] { 10620001 }, null)]
[InlineData(20002, 2, 600201, 2, 4, new[] { 10620001, 10630001 }, null)]
// Nine plus zero
[InlineData(
20001,
9,
800201,
9,
0,
new[] { 10610000, 10610000, 10610000, 10610000, 10610000, 10610000, 10620000, 10620000, 10620000 },
null
)]
[InlineData(
20002,
9,
600201,
9,
0,
new[] { 10620001, 10620001, 10620001, 10620001, 10620001, 10630001, 10630001, 10630001, 10630001 },
null
)]
// Ten plus one
[InlineData(
20001,
10,
800201,
10,
0,
new[] { 10610000, 10610000, 10610000, 10610000, 10610000, 10610000, 10610000, 10610000, 10620000, 10620000, 10620000 },
null
)]
[InlineData(
20002,
10,
600201,
10,
0,
new[] { 10620001, 10620001, 10620001, 10620001, 10620001, 10620001, 10630001, 10620001, 10630001, 10630001, 10630001 },
null
)]
// fail by invalid group
[InlineData(100003, 1, null, 0, 0, new int[] { }, typeof(RowNotInTableException))]
// fail by not enough material
[InlineData(20001, 1, 800201, 0, 0, new int[] { }, typeof(NotEnoughMaterialException))]
[InlineData(20001, 2, 800201, 0, 0, new int[] { }, typeof(NotEnoughMaterialException))]
// Fail by exceeding summon limit
[InlineData(20001, 11, 800201, 22, 1, new int[] { }, typeof(InvalidSummonCountException))]
// 15 recipes
[InlineData(20002, 1, 600201, 1, 5341, new[] { 10650006 }, null)]
public void Execute(
int groupId,
int summonCount,
int? materialId,
int materialCount,
int seed,
int[] expectedEquipmentId,
Type expectedExc
)
{
var random = new TestRandom(seed);
var state = _initialState;
state = state.SetState(
Addresses.TableSheet.Derive(nameof(SummonSheet)),
_tableSheets.SummonSheet.Serialize()
);

if (!(materialId is null))
{
var materialSheet = _tableSheets.MaterialItemSheet;
var material = materialSheet.OrderedList.FirstOrDefault(m => m.Id == materialId);
_avatarState.inventory.AddItem(
ItemFactory.CreateItem(material, random),
materialCount * _tableSheets.SummonSheet[groupId].CostMaterialCount
);
state = state
.SetState(_avatarAddress, _avatarState.SerializeV2())
.SetState(
_avatarAddress.Derive(LegacyInventoryKey),
_avatarState.inventory.Serialize()
)
.SetState(
_avatarAddress.Derive(LegacyWorldInformationKey),
_avatarState.worldInformation.Serialize()
)
.SetState(
_avatarAddress.Derive(LegacyQuestListKey),
_avatarState.questList.Serialize()
)
;
}

var action = new RuneSummon
{
AvatarAddress = _avatarAddress,
GroupId = groupId,
SummonCount = summonCount,
};

if (expectedExc == null)
{
// Success
var ctx = new ActionContext
{
PreviousState = state,
Signer = _agentAddress,
BlockIndex = 1,
};
ctx.SetRandom(random);
var nextState = action.Execute(ctx);

var equipments = nextState.GetAvatarStateV2(_avatarAddress).inventory.Equipments
.ToList();
Assert.Equal(expectedEquipmentId.Length, equipments.Count);

var checkedEquipments = new List<Guid>();
foreach (var equipmentId in expectedEquipmentId)
{
var resultEquipment = equipments.First(e =>
e.Id == equipmentId && !checkedEquipments.Contains(e.ItemId)
);

checkedEquipments.Add(resultEquipment.ItemId);
Assert.NotNull(resultEquipment);
Assert.Equal(1, resultEquipment.RequiredBlockIndex);
Assert.True(resultEquipment.optionCountFromCombination > 0);
}

nextState.GetAvatarStateV2(_avatarAddress).inventory
.TryGetItem((int)materialId!, out var resultMaterial);
Assert.Equal(0, resultMaterial?.count ?? 0);
}
else
{
// Failure
Assert.Throws(expectedExc, () =>
{
action.Execute(new ActionContext
{
PreviousState = state,
Signer = _agentAddress,
BlockIndex = 1,
RandomSeed = random.Seed,
});
});
}
}
}
}
11 changes: 11 additions & 0 deletions Lib9c.Abstractions/IRuneSummonV1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Libplanet.Crypto;

namespace Lib9c.Abstractions;

Check failure on line 3 in Lib9c.Abstractions/IRuneSummonV1.cs

View workflow job for this annotation

GitHub Actions / build-for-unity

Feature 'file-scoped namespace' is not available in C# 8.0. Please use language version 10.0 or greater.

Check failure on line 3 in Lib9c.Abstractions/IRuneSummonV1.cs

View workflow job for this annotation

GitHub Actions / build-for-unity

Feature 'file-scoped namespace' is not available in C# 8.0. Please use language version 10.0 or greater.

Check failure on line 3 in Lib9c.Abstractions/IRuneSummonV1.cs

View workflow job for this annotation

GitHub Actions / build-for-unity

Feature 'file-scoped namespace' is not available in C# 8.0. Please use language version 10.0 or greater.

Check failure on line 3 in Lib9c.Abstractions/IRuneSummonV1.cs

View workflow job for this annotation

GitHub Actions / build-for-unity

Feature 'file-scoped namespace' is not available in C# 8.0. Please use language version 10.0 or greater.

public interface IRuneSummonV1
{
Address AvatarAddress { get; }
int GroupId { get; }

int SummonCount { get; }
}
Loading

0 comments on commit 9326922

Please sign in to comment.