Skip to content

Commit

Permalink
Merge pull request #2258 from planetarium/feature/rune-summon
Browse files Browse the repository at this point in the history
Introduce RuneSummon
  • Loading branch information
ipdae authored Dec 4, 2023
2 parents 5b0c391 + 4e6eb51 commit 1dc61aa
Show file tree
Hide file tree
Showing 10 changed files with 541 additions and 8 deletions.
7 changes: 7 additions & 0 deletions .Lib9c.Tests/Action/ActionEvaluationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public ActionEvaluationTest()
[InlineData(typeof(EndPledge))]
[InlineData(typeof(CreatePledge))]
[InlineData(typeof(TransferAssets))]
[InlineData(typeof(RuneSummon))]
public void Serialize_With_MessagePack(Type actionType)
{
var action = GetAction(actionType);
Expand Down Expand Up @@ -462,6 +463,12 @@ private ActionBase GetAction(Type type)
{
(_signer, 1 * _currency),
}),
RuneSummon _ => new RuneSummon
{
AvatarAddress = _sender,
GroupId = 20001,
SummonCount = 10,
},
_ => throw new InvalidCastException(),
};
}
Expand Down
15 changes: 11 additions & 4 deletions .Lib9c.Tests/Action/Summon/AuraSummonTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace Lib9c.Tests.Action.Summon
using Nekoyume.Action.Exceptions;
using Nekoyume.Model.Item;
using Nekoyume.Model.State;
using Nekoyume.TableData;
using Nekoyume.TableData.Summon;
using Xunit;
using static SerializeKeys;
Expand Down Expand Up @@ -176,6 +177,8 @@ public void CumulativeRatio(string version, int groupId)
[InlineData("V1", 10001, 11, 800201, 22, 1, new int[] { }, typeof(InvalidSummonCountException))]
// 15 recipes
[InlineData("V2", 10002, 1, 600201, 1, 5341, new[] { 10650006 }, null)]
// 15 recipes
[InlineData("V3", 20001, 1, 600201, 1, 5341, new int[] { }, typeof(SheetRowNotFoundException))]
public void Execute(
string version,
int groupId,
Expand All @@ -189,10 +192,14 @@ Type expectedExc
{
var random = new TestRandom(seed);
var state = _initialState;
state = state.SetState(
Addresses.TableSheet.Derive(nameof(SummonSheet)),
version == "V1" ? SummonSheetFixtures.V1.Serialize() : SummonSheetFixtures.V2.Serialize()
);
var sheet = version switch
{
"V1" => SummonSheetFixtures.V1.Serialize(),
"V2" => SummonSheetFixtures.V2.Serialize(),
"V3" => SummonSheetFixtures.V3.Serialize(),
_ => throw new ArgumentOutOfRangeException(nameof(version), version, null)
};
state = state.SetState(Addresses.TableSheet.Derive(nameof(SummonSheet)), sheet);

if (!(materialId is null))
{
Expand Down
261 changes: 261 additions & 0 deletions .Lib9c.Tests/Action/Summon/RuneSummonTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
namespace Lib9c.Tests.Action.Summon
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
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;
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)
.MintAsset(context, _avatarAddress, 100 * Currencies.GetRune("RUNESTONE_FENRIR1"))
.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)]
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]
[ClassData(typeof(ExecuteMemeber))]
public void Execute(
int groupId,
int summonCount,
int? materialId,
int materialCount,
int seed,
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 result = RuneSummon.SimulateSummon(
_tableSheets.RuneSheet,
_tableSheets.SummonSheet[groupId],
summonCount,
new TestRandom(seed)
);
foreach (var pair in result)
{
var currency = pair.Key;
var prevBalance = state.GetBalance(_avatarAddress, currency);
var balance = nextState.GetBalance(_avatarAddress, currency);
Assert.Equal(currency * pair.Value, balance - prevBalance);
}

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,
});
});
}
}

private class ExecuteMemeber : IEnumerable<object[]>
{
private readonly List<object[]> _data = new ()
{
new object[]
{
20001, 1, 600201, 1, 1, null,
},
new object[]
{
20001, 2, 600201, 2, 54, null,
},
// Nine plus zero
new object[]
{
20001,
9,
600201,
9,
0,
null,
},
// Ten plus one
new object[]
{
20001,
10,
600201,
10,
0,
null,
},
// fail by invalid group
new object[]
{
100003, 1, null, 0, 0, typeof(RowNotInTableException),
},
// fail by not enough material
new object[]
{
20001, 1, 600201, 0, 0, typeof(NotEnoughMaterialException),
},
// Fail by exceeding summon limit
new object[]
{
20001, 11, 600201, 22, 1, typeof(InvalidSummonCountException),
},
new object[]
{
10002, 1, 600201, 1, 1, typeof(SheetRowNotFoundException),
},
};

public IEnumerator<object[]> GetEnumerator() => _data.GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() => _data.GetEnumerator();
}
}
}
6 changes: 6 additions & 0 deletions .Lib9c.Tests/Fixtures/TableCSV/Summon/SummonSheetFixtures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,11 @@ public class SummonSheetFixtures
@"groupID,cost_material,cost_material_count,cost_ncg,recipe1ID,recipe1ratio,recipe2ID,recipe2ratio,recipe3ID,recipe3ratio,recipe4ID,recipe4ratio,recipe5ID,recipe5ratio,recipe6ID,recipe6ratio,recipe7ID,recipe7ratio,recipe8ID,recipe8ratio,recipe9ID,recipe9ratio,recipe10ID,recipe10ratio,recipe11ID,recipe11ratio,recipe12ID,recipe12ratio,recipe13ID,recipe13ratio,recipe14ID,recipe14ratio,recipe15ID,recipe15ratio
10001,800201,10,0,171,70,172,29,173,1,,,,,,,,,,,,,,,,,,,,,,,,
10002,600201,20,0,174,6500,175,2940,176,510,177,45,178,5,179,6500,180,2940,181,510,182,45,183,5,184,6500,185,2940,186,510,187,45,188,5";

public const string V3 = @"groupID,cost_material,cost_material_count,cost_ncg,recipe1ID,recipe1ratio,recipe2ID,recipe2ratio,recipe3ID,recipe3ratio,recipe4ID,recipe4ratio,recipe5ID,recipe5ratio,recipe6ID,recipe6ratio,recipe7ID,recipe7ratio,recipe8ID,recipe8ratio,recipe9ID,recipe9ratio,recipe10ID,recipe10ratio,recipe11ID,recipe11ratio,recipe12ID,recipe12ratio,recipe13ID,recipe13ratio,recipe14ID,recipe14ratio,recipe15ID,recipe15ratio
10001,800201,10,0,171,70,172,29,173,1,,,,,,,,,,,,,,,,,,,,,,,,
10002,600201,20,0,174,6500,175,2940,176,510,177,45,178,5,179,6500,180,2940,181,510,182,45,183,5,184,6500,185,2940,186,510,187,45,188,5
20001,600201,10,0,10021,20,10022,20,10023,20,10024,20,10025,60,10026,60,10027,60,10028,60,10001,40,10002,100,10003,200,10011,40,10012,100,10013,200,,
";
}
}
12 changes: 12 additions & 0 deletions Lib9c.Abstractions/IRuneSummonV1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Libplanet.Crypto;

namespace Lib9c.Abstractions
{
public interface IRuneSummonV1
{
Address AvatarAddress { get; }
int GroupId { get; }

int SummonCount { get; }
}
}
Loading

0 comments on commit 1dc61aa

Please sign in to comment.