-
Notifications
You must be signed in to change notification settings - Fork 53
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
248 additions
and
23 deletions.
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
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,145 @@ | ||
namespace Lib9c.Tests.Action | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using Bencodex.Types; | ||
using Libplanet.Action; | ||
using Libplanet.Action.State; | ||
using Libplanet.Crypto; | ||
using Libplanet.Types.Assets; | ||
using Nekoyume; | ||
using Nekoyume.Action; | ||
using Nekoyume.Action.Loader; | ||
using Nekoyume.Model.State; | ||
using Nekoyume.Module; | ||
using Nekoyume.TableData; | ||
using Xunit; | ||
using static Lib9c.SerializeKeys; | ||
|
||
public class RemoveLegacyAgentAvatarTest | ||
{ | ||
private readonly TableSheets _tableSheets; | ||
|
||
public RemoveLegacyAgentAvatarTest() | ||
{ | ||
var sheets = TableSheetsImporter.ImportSheets(); | ||
sheets[nameof(CharacterSheet)] = string.Join( | ||
Environment.NewLine, | ||
"id,_name,size_type,elemental_type,hp,atk,def,cri,hit,spd,lv_hp,lv_atk,lv_def,lv_cri,lv_hit,lv_spd,attack_range,run_speed", | ||
"100010,전사,S,0,300,20,10,10,90,70,12,0.8,0.4,0,3.6,2.8,2,3"); | ||
_tableSheets = new TableSheets(sheets); | ||
} | ||
|
||
[Theory] | ||
[InlineData(1)] | ||
[InlineData(2)] | ||
public void RemoveLegacyAgentAvatar(int legacyAvatarVersion) | ||
{ | ||
var avatarIndex = 1; | ||
var agentAddress = new PrivateKey().Address; | ||
var agentState = new AgentState(agentAddress); | ||
var avatarAddress = agentAddress.Derive(string.Format(CultureInfo.InvariantCulture, CreateAvatar.DeriveFormat, avatarIndex)); | ||
agentState.avatarAddresses.Add(avatarIndex, avatarAddress); | ||
|
||
var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); | ||
var questListAddress = avatarAddress.Derive(LegacyQuestListKey); | ||
var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); | ||
|
||
var weekly = new WeeklyArenaState(0); | ||
var gameConfigState = new GameConfigState(); | ||
gameConfigState.Set(_tableSheets.GameConfigSheet); | ||
var currency = Currency.Legacy("NCG", 2, null); | ||
|
||
var avatarState = new AvatarState( | ||
avatarAddress, | ||
agentAddress, | ||
456, | ||
_tableSheets.GetAvatarSheets(), | ||
gameConfigState, | ||
default); | ||
|
||
MockWorldState mock = new MockWorldState() | ||
.SetState( | ||
ReservedAddresses.LegacyAccount, | ||
GoldCurrencyState.Address, | ||
new GoldCurrencyState(currency, 0).Serialize()) | ||
.SetState( | ||
ReservedAddresses.LegacyAccount, | ||
weekly.address, | ||
weekly.Serialize()) | ||
.SetState( | ||
ReservedAddresses.LegacyAccount, | ||
Addresses.GoldDistribution, | ||
new List()) | ||
.SetState( | ||
ReservedAddresses.LegacyAccount, | ||
gameConfigState.address, | ||
gameConfigState.Serialize()); | ||
|
||
switch (legacyAvatarVersion) | ||
{ | ||
case 1: | ||
mock = mock | ||
.SetState( | ||
ReservedAddresses.LegacyAccount, | ||
agentAddress, | ||
agentState.SerializeList()) | ||
.SetState( | ||
ReservedAddresses.LegacyAccount, | ||
avatarAddress, | ||
MigrationAvatarState.LegacySerializeV1(avatarState)); | ||
break; | ||
case 2: | ||
mock = mock | ||
.SetState( | ||
ReservedAddresses.LegacyAccount, | ||
agentAddress, | ||
agentState.SerializeList()) | ||
.SetState( | ||
ReservedAddresses.LegacyAccount, | ||
avatarAddress, | ||
MigrationAvatarState.LegacySerializeV1(avatarState)) | ||
.SetState( | ||
ReservedAddresses.LegacyAccount, | ||
inventoryAddress, | ||
avatarState.inventory.Serialize()) | ||
.SetState( | ||
ReservedAddresses.LegacyAccount, | ||
worldInformationAddress, | ||
avatarState.questList.Serialize()) | ||
.SetState( | ||
ReservedAddresses.LegacyAccount, | ||
questListAddress, | ||
avatarState.questList.Serialize()); | ||
break; | ||
default: | ||
throw new ArgumentException($"Invalid legacy avatar version: {legacyAvatarVersion}"); | ||
} | ||
|
||
IAction action = new RemoveLegacyAgentAvatar | ||
{ | ||
AgentAddresses = new List<Address> { agentAddress }, | ||
}; | ||
|
||
var plainValue = action.PlainValue; | ||
var actionLoader = new NCActionLoader(); | ||
action = actionLoader.LoadAction(123, plainValue); | ||
|
||
var states = new World(mock); | ||
IWorld nextState = action.Execute( | ||
new ActionContext() | ||
{ | ||
PreviousState = states, | ||
Miner = default, | ||
} | ||
); | ||
|
||
Assert.Null(nextState.GetLegacyState(agentAddress)); | ||
Assert.Null(nextState.GetLegacyState(avatarAddress)); | ||
Assert.Null(nextState.GetLegacyState(inventoryAddress)); | ||
Assert.Null(nextState.GetLegacyState(worldInformationAddress)); | ||
Assert.Null(nextState.GetLegacyState(questListAddress)); | ||
} | ||
} | ||
} |
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,94 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using System.Linq; | ||
using Bencodex.Types; | ||
using Libplanet.Action; | ||
using Libplanet.Action.State; | ||
using Libplanet.Crypto; | ||
using Nekoyume.Module; | ||
using Serilog; | ||
using static Lib9c.SerializeKeys; | ||
|
||
namespace Nekoyume.Action | ||
{ | ||
[ActionType(TypeIdentifier)] | ||
public class RemoveLegacyAgentAvatar : ActionBase | ||
{ | ||
public const string TypeIdentifier = "remove_legacy_agent_avatar"; | ||
|
||
public List<Address> AgentAddresses; | ||
|
||
public RemoveLegacyAgentAvatar() | ||
{ | ||
} | ||
|
||
public override IValue PlainValue => Dictionary.Empty | ||
.Add("type_id", TypeIdentifier) | ||
.Add( | ||
"values", | ||
Dictionary.Empty.Add( | ||
"agent_addresses", | ||
new List(AgentAddresses.Select(address => address.Bencoded)))); | ||
|
||
public override void LoadPlainValue(IValue plainValue) | ||
{ | ||
var asDict = (Dictionary)((Dictionary)plainValue)["values"]; | ||
AgentAddresses = ((List)asDict["agent_addresses"]).Select(v => new Address(v)).ToList(); | ||
} | ||
|
||
public override IWorld Execute(IActionContext context) | ||
{ | ||
context.UseGas(1); | ||
var states = context.PreviousState; | ||
var removeStarted = DateTimeOffset.UtcNow; | ||
Log.Debug( | ||
"Removing legacy agent/avatar states in block index #{Index} started", | ||
context.BlockIndex); | ||
|
||
const int maxAvatarCount = 3; | ||
var avatarAddresses = Enumerable | ||
.Range(0, AgentAddresses.Count * maxAvatarCount) | ||
.Select(i => AgentAddresses[i / maxAvatarCount] | ||
.Derive( | ||
string.Format(CultureInfo.InvariantCulture, CreateAvatar.DeriveFormat, i % maxAvatarCount))) | ||
.ToList(); | ||
|
||
foreach (var address in AgentAddresses) | ||
{ | ||
// Delete AgentState in Legacy | ||
var started = DateTimeOffset.UtcNow; | ||
Log.Debug("Removing agent {Address} from legacy account", address); | ||
states = states.SetLegacyState(address, null); | ||
Log.Debug( | ||
"Removing agent {Address} finished in: {Elapsed} ms", | ||
address, | ||
(DateTimeOffset.UtcNow - started).Milliseconds); | ||
} | ||
|
||
foreach (var address in avatarAddresses) | ||
{ | ||
// Delete AvatarState in Legacy | ||
var started = DateTimeOffset.UtcNow; | ||
Log.Debug( | ||
"Removing avatar {Address} and its related states from legacy account", | ||
address); | ||
states = states.SetLegacyState(address, null); | ||
states = states.SetLegacyState(address.Derive(LegacyInventoryKey), null); | ||
states = states.SetLegacyState(address.Derive(LegacyQuestListKey), null); | ||
states = states.SetLegacyState(address.Derive(LegacyWorldInformationKey), null); | ||
Log.Debug( | ||
"Removing avatar {Address} and its related states finished in: {Elapsed} ms", | ||
address, | ||
(DateTimeOffset.UtcNow - started).Milliseconds); | ||
} | ||
|
||
Log.Debug( | ||
"Removing {Count} legacy agents in block index #{Index} finished in: {Elapsed} ms", | ||
AgentAddresses.Count, | ||
context.BlockIndex, | ||
(DateTimeOffset.UtcNow - removeStarted).Milliseconds); | ||
return states; | ||
} | ||
} | ||
} |