public MimisbrunnrBattle3Test() { var sheets = TableSheetsImporter.ImportSheets(); _tableSheets = new TableSheets(sheets); var privateKey = new PrivateKey(); _agentAddress = privateKey.PublicKey.ToAddress(); var agentState = new AgentState(_agentAddress); _avatarAddress = _agentAddress.Derive("avatar"); _rankingMapAddress = _avatarAddress.Derive("ranking_map"); var avatarState = new AvatarState( _avatarAddress, _agentAddress, 0, _tableSheets.GetAvatarSheets(), new GameConfigState(sheets[nameof(GameConfigSheet)]), _rankingMapAddress ) { level = 400, }; agentState.avatarAddresses.Add(0, _avatarAddress); _weeklyArenaState = new WeeklyArenaState(0); _initialState = new State() .SetState(_weeklyArenaState.address, _weeklyArenaState.Serialize()) .SetState(_agentAddress, agentState.Serialize()) .SetState(_avatarAddress, avatarState.Serialize()) .SetState(_rankingMapAddress, new RankingMapState(_rankingMapAddress).Serialize()); foreach (var(key, value) in sheets) { _initialState = _initialState .SetState(Addresses.TableSheet.Derive(key), value.Serialize()); } }
public DailyRewardTest2(ITestOutputHelper outputHelper) { Log.Logger = new LoggerConfiguration() .MinimumLevel.Verbose() .WriteTo.TestOutput(outputHelper) .CreateLogger(); _initialState = new State(); var sheets = TableSheetsImporter.ImportSheets(); foreach (var(key, value) in sheets) { _initialState = _initialState .SetState(Addresses.TableSheet.Derive(key), value.Serialize()); } var tableSheets = new TableSheets(sheets); _agentAddress = new PrivateKey().ToAddress(); var agentState = new AgentState(_agentAddress); _avatarAddress = new PrivateKey().ToAddress(); var rankingMapAddress = new PrivateKey().ToAddress(); var avatarState = new AvatarState( _avatarAddress, _agentAddress, 0, tableSheets.GetAvatarSheets(), new GameConfigState(), rankingMapAddress) { actionPoint = 0, }; agentState.avatarAddresses[0] = _avatarAddress; _initialState = _initialState .SetState(Addresses.GameConfig, new GameConfigState().Serialize()) .SetState(_agentAddress, agentState.Serialize()) .SetState(_avatarAddress, avatarState.Serialize()); }
public static string GetSheetCsv <T>(this IAccountStateDelta states) where T : ISheet, new() { var address = Addresses.GetSheetAddress <T>(); var value = states.GetState(address); if (value is null) { Log.Warning($"{nameof(T)} is null ({0})", address.ToHex()); throw new FailedLoadStateException(nameof(T)); } try { return(value.ToDotnetString()); } catch (Exception e) { Log.Error(e, $"Unexpected error occurred during {nameof(T)}()"); throw; } }
public ActionContext( Address signer, Address miner, long blockIndex, IAccountStateDelta previousStates, int randomSeed, bool rehearsal = false, ITrie?previousBlockStatesTrie = null, bool blockAction = false ) { Signer = signer; Miner = miner; BlockIndex = blockIndex; Rehearsal = rehearsal; PreviousStates = previousStates; Random = new Random(randomSeed); _randomSeed = randomSeed; _previousBlockStatesTrie = previousBlockStatesTrie; BlockAction = blockAction; }
public IAccountStateDelta MinerReward(IActionContext ctx, IAccountStateDelta states) { // 마이닝 보상 // https://www.notion.so/planetarium/Mining-Reward-b7024ef463c24ebca40a2623027d497d Currency currency = states.GetGoldCurrency(); FungibleAssetValue defaultMiningReward = currency * 10; var countOfHalfLife = (int)Math.Pow(2, Convert.ToInt64((ctx.BlockIndex - 1) / 12614400)); FungibleAssetValue miningReward = defaultMiningReward.DivRem(countOfHalfLife, out FungibleAssetValue _); if (miningReward >= FungibleAssetValue.Parse(currency, "1.25")) { states = states.TransferAsset( GoldCurrencyState.Address, ctx.Miner, miningReward ); } return(states); }
public MakeInitialStateResult( IAccountStateDelta state, CreateTestbed testbed, AgentState agentState, AvatarState avatarState, GoldCurrencyState goldCurrencyState, Address rankingMapAddress, TableSheets tableSheets, FungibleAssetValue currencyGold, FungibleAssetValue agentCurrencyGold) { _state = state; _testbed = testbed; _agentState = agentState; _avatarState = avatarState; _goldCurrencyState = goldCurrencyState; _rankingMapAddress = rankingMapAddress; _tableSheets = tableSheets; _currencyGold = currencyGold; _agentCurrencyGold = agentCurrencyGold; }
public static bool TryGetState <T>(this IAccountStateDelta states, Address address, out T result) where T : IValue { IValue raw = states.GetState(address); if (raw is T v) { result = v; return(true); } Log.Error( "Expected a {0}, but got invalid state ({1}): ({2}) {3}", typeof(T).Name, address.ToHex(), raw?.GetType().Name, raw ); result = default; return(false); }
public override IAccountStateDelta Execute(IActionContext context) { IImmutableSet <string> usedWeapons = ImmutableHashSet <string> .Empty; IImmutableSet <string> targets = ImmutableHashSet <string> .Empty; IAccountStateDelta previousStates = context.PreviousStates; object value = previousStates.GetState(TargetAddress); if (!ReferenceEquals(value, null)) { var previousResult = BattleResult.FromBencodex((Bencodex.Types.Dictionary)value); usedWeapons = previousResult.UsedWeapons; targets = previousResult.Targets; } usedWeapons = usedWeapons.Add(Weapon); targets = targets.Add(Target); var result = new BattleResult(usedWeapons, targets); return(previousStates.SetState(TargetAddress, result.ToBencodex())); }
public CancelMonsterCollectTest() { _signer = default; _state = new State(); Dictionary <string, string> sheets = TableSheetsImporter.ImportSheets(); _tableSheets = new TableSheets(sheets); var agentState = new AgentState(_signer); var currency = new Currency("NCG", 2, minters: null); var goldCurrencyState = new GoldCurrencyState(currency); _state = _state .SetState(_signer, agentState.Serialize()) .SetState(Addresses.GoldCurrency, goldCurrencyState.Serialize()); foreach ((string key, string value) in sheets) { _state = _state .SetState(Addresses.TableSheet.Derive(key), value.Serialize()); } }
public void ExecuteThrowNotEnoughClearedStageLevelException() { _initialState = _initialState .SetState(_slotAddress, new CombinationSlotState(_slotAddress, 0).Serialize()); var action = new CombinationConsumable0() { AvatarAddress = _avatarAddress, recipeId = 1, slotIndex = 0, }; Assert.Throws <NotEnoughClearedStageLevelException>(() => action.Execute(new ActionContext() { PreviousStates = _initialState, Signer = _agentAddress, BlockIndex = 1, Random = _random, }) ); }
public void Execute_Throw_InvalidLevelException(int prevLevel, int level) { Address collectionAddress = MonsterCollectionState0.DeriveAddress(_signer, 0); MonsterCollectionState0 monsterCollectionState = new MonsterCollectionState0(collectionAddress, prevLevel, 0, _tableSheets.MonsterCollectionRewardSheet); _state = _state.SetState(collectionAddress, monsterCollectionState.Serialize()); CancelMonsterCollect action = new CancelMonsterCollect { level = level, collectRound = 0, }; Assert.Throws <InvalidLevelException>(() => action.Execute(new ActionContext { PreviousStates = _state, Signer = _signer, BlockIndex = 0, }) ); }
public IAccountStateDelta ResetChallengeCount(IActionContext ctx, IAccountStateDelta states) { var gameConfigState = states.GetGameConfigState(); var index = Math.Max((int)ctx.BlockIndex / gameConfigState.WeeklyArenaInterval, 0); var weeklyAddress = WeeklyArenaState.DeriveAddress(index); var rawWeekly = (Dictionary)states.GetState(weeklyAddress); var resetIndex = rawWeekly["resetIndex"].ToLong(); if (ctx.BlockIndex - resetIndex >= gameConfigState.DailyArenaInterval) { var weekly = new WeeklyArenaState(rawWeekly); if (resetIndex >= RankingBattle.UpdateTargetBlockIndex) { // Reset count each ArenaInfo. weekly.ResetIndex = ctx.BlockIndex; var listAddress = weeklyAddress.Derive("address_list"); if (states.TryGetState(listAddress, out List rawList)) { var addressList = rawList.ToList(StateExtensions.ToAddress); foreach (var address in addressList) { var infoAddress = weeklyAddress.Derive(address.ToByteArray()); if (states.TryGetState(infoAddress, out Dictionary rawInfo)) { var info = new ArenaInfo(rawInfo); info.ResetCount(); states = states.SetState(infoAddress, info.Serialize()); } } } } else { // Run legacy ResetCount. weekly.ResetCount(ctx.BlockIndex); } states = states.SetState(weeklyAddress, weekly.Serialize()); } return(states); }
public void Execute() { var agentAddress = new PrivateKey().ToAddress(); var avatarAddress = new PrivateKey().ToAddress(); var avatarState = new AvatarState( avatarAddress, agentAddress, 0, _tableSheets.GetAvatarSheets(), new GameConfigState(), default ); var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; var admin = new Address("8d9f76aF8Dc5A812aCeA15d8bf56E2F790F47fd7"); var state = new State(ImmutableDictionary <Address, IValue> .Empty .Add(AdminState.Address, new AdminState(admin, 100).Serialize()) .Add(avatarAddress, avatarState.SerializeV2()) ); var action = new MigrationAvatarState { avatarStates = new List <Dictionary> { (Dictionary)avatarState.Serialize(), }, }; IAccountStateDelta nextState = action.Execute(new ActionContext() { PreviousStates = state, Signer = admin, BlockIndex = 1, }); var nextAvatarState = nextState.GetAvatarStateV2(avatarAddress); Assert.NotNull(nextAvatarState.inventory); Assert.NotNull(nextAvatarState.worldInformation); Assert.NotNull(nextAvatarState.questList); }
internal ActionEvaluation EvaluateBlockAction( Block <T> block, IReadOnlyList <ActionEvaluation> txActionEvaluations) { if (Policy.BlockAction is null) { var message = "To evaluate block action, Policy.BlockAction must not be null."; throw new InvalidOperationException(message); } IAccountStateDelta lastStates = null; if (!(txActionEvaluations is null) && txActionEvaluations.Count > 0) { lastStates = txActionEvaluations[txActionEvaluations.Count - 1].OutputStates; } Address miner = block.Miner.GetValueOrDefault(); var minerState = GetStates(new[] { miner }, block.PreviousHash) .GetValueOrDefault(miner); if (lastStates is null) { lastStates = new AccountStateDeltaImpl(a => minerState); } else if (lastStates.GetState(miner) is null) { lastStates = lastStates.SetState(miner, minerState); } return(ActionEvaluation.EvaluateActionsGradually( block.Hash, block.Index, lastStates, miner, miner, Array.Empty <byte>(), new[] { Policy.BlockAction }.ToImmutableList()).First()); }
public void Execute_Throw_MonsterCollectionExpiredException() { Address collectionAddress = MonsterCollectionState0.DeriveAddress(_signer, 0); MonsterCollectionState0 prevMonsterCollectionState = new MonsterCollectionState0(collectionAddress, 1, 0, _tableSheets.MonsterCollectionRewardSheet); Assert.Equal(MonsterCollectionState0.ExpirationIndex, prevMonsterCollectionState.ExpiredBlockIndex); _initialState = _initialState.SetState(collectionAddress, prevMonsterCollectionState.Serialize()); MonsterCollect0 action = new MonsterCollect0 { level = 2, collectionRound = 0, }; Assert.Throws <MonsterCollectionExpiredException>(() => action.Execute(new ActionContext { PreviousStates = _initialState, Signer = _signer, BlockIndex = prevMonsterCollectionState.ExpiredBlockIndex + 1, })); }
public IAccountStateDelta GenesisGoldDistribution(IActionContext ctx, IAccountStateDelta states) { IEnumerable <GoldDistribution> goldDistributions = states.GetGoldDistribution(); var index = ctx.BlockIndex; Currency goldCurrency = states.GetGoldCurrency(); Address fund = GoldCurrencyState.Address; foreach (GoldDistribution distribution in goldDistributions) { BigInteger amount = distribution.GetAmount(index); if (amount <= 0) { continue; } states = states.TransferAsset( fund, distribution.Address, goldCurrency * amount ); } return(states); }
public IAccountStateDelta WeeklyArenaRankingBoard2(IActionContext ctx, IAccountStateDelta states) { var gameConfigState = states.GetGameConfigState(); var index = Math.Max((int)ctx.BlockIndex / gameConfigState.WeeklyArenaInterval, 0); var weeklyAddress = WeeklyArenaState.DeriveAddress(index); var rawWeekly = (Dictionary)states.GetState(weeklyAddress); var nextIndex = index + 1; var nextWeekly = states.GetWeeklyArenaState(nextIndex); if (nextWeekly is null) { nextWeekly = new WeeklyArenaState(nextIndex); states = states.SetState(nextWeekly.address, nextWeekly.Serialize()); } var resetIndex = rawWeekly["resetIndex"].ToLong(); // Beginning block of a new weekly arena. if (ctx.BlockIndex % gameConfigState.WeeklyArenaInterval == 0 && index > 0) { var prevWeeklyAddress = WeeklyArenaState.DeriveAddress(index - 1); var rawPrevWeekly = (Dictionary)states.GetState(prevWeeklyAddress); if (!rawPrevWeekly["ended"].ToBoolean()) { rawPrevWeekly = rawPrevWeekly.SetItem("ended", true.Serialize()); var weekly = new WeeklyArenaState(rawWeekly); var prevWeekly = new WeeklyArenaState(rawPrevWeekly); weekly.Update(prevWeekly, ctx.BlockIndex); states = states.SetState(prevWeeklyAddress, rawPrevWeekly); states = states.SetState(weeklyAddress, weekly.Serialize()); } } else if (ctx.BlockIndex - resetIndex >= gameConfigState.DailyArenaInterval) { var weekly = new WeeklyArenaState(rawWeekly); weekly.ResetCount(ctx.BlockIndex); states = states.SetState(weeklyAddress, weekly.Serialize()); } return(states); }
public CombinationConsumable4Test() { _agentAddress = default; _avatarAddress = _agentAddress.Derive("avatar"); _slotAddress = _avatarAddress.Derive( string.Format( CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, 0 ) ); _sheets = TableSheetsImporter.ImportSheets(); _random = new TestRandom(); _tableSheets = new TableSheets(_sheets); var agentState = new AgentState(_agentAddress); agentState.avatarAddresses[0] = _avatarAddress; var gameConfigState = new GameConfigState(); _avatarState = new AvatarState( _avatarAddress, _agentAddress, 1, _tableSheets.GetAvatarSheets(), gameConfigState, default ); _initialState = new State() .SetState(_agentAddress, agentState.Serialize()) .SetState(_avatarAddress, _avatarState.Serialize()); foreach (var(key, value) in _sheets) { _initialState = _initialState.SetState(Addresses.TableSheet.Derive(key), value.Serialize()); } }
public void GetSetState() { IAccountStateDelta init = new AccountStateDeltaImpl(GetState); IAccountStateDelta a = init.SetState(_addr[0], "A"); Assert.Equal("A", a.GetState(_addr[0])); Assert.Equal("a", init.GetState(_addr[0])); Assert.Equal("b", a.GetState(_addr[1])); Assert.Equal("b", init.GetState(_addr[1])); Assert.Null(a.GetState(_addr[2])); Assert.Null(init.GetState(_addr[2])); Assert.Equal( new[] { _addr[0] }.ToImmutableHashSet(), a.UpdatedAddresses ); Assert.Empty(init.UpdatedAddresses); IAccountStateDelta b = a.SetState(_addr[0], "z"); Assert.Equal("z", b.GetState(_addr[0])); Assert.Equal("A", a.GetState(_addr[0])); Assert.Equal("a", init.GetState(_addr[0])); Assert.Equal("b", b.GetState(_addr[1])); Assert.Equal("b", a.GetState(_addr[1])); Assert.Null(b.GetState(_addr[2])); Assert.Null(a.GetState(_addr[2])); Assert.Equal( new[] { _addr[0] }.ToImmutableHashSet(), a.UpdatedAddresses ); Assert.Empty(init.UpdatedAddresses); IAccountStateDelta c = b.SetState(_addr[0], "a"); Assert.Equal("a", c.GetState(_addr[0])); Assert.Equal("z", b.GetState(_addr[0])); Assert.Empty(c.UpdatedAddresses); Assert.Empty(init.UpdatedAddresses); }
public void Execute_Throw_InsufficientBalanceException() { Address collectionAddress = MonsterCollectionState0.DeriveAddress(_signer, 0); MonsterCollectionState0 monsterCollectionState = new MonsterCollectionState0(collectionAddress, 1, 0, _tableSheets.MonsterCollectionRewardSheet); _state = _state.SetState(collectionAddress, monsterCollectionState.Serialize()); ClaimMonsterCollectionReward0 action = new ClaimMonsterCollectionReward0 { avatarAddress = _avatarAddress, collectionRound = 0, }; Assert.Throws <InsufficientBalanceException>(() => action.Execute(new ActionContext { PreviousStates = _state, Signer = _signer, BlockIndex = MonsterCollectionState0.ExpirationIndex, Random = new TestRandom(), }) ); }
public static IEnumerable <GoldDistribution> GetGoldDistribution( this IAccountStateDelta states) { var value = states.GetState(Addresses.GoldDistribution); if (value is null) { Log.Warning($"{nameof(GoldDistribution)} is null ({0})", Addresses.GoldDistribution.ToHex()); return(null); } try { var goldDistributions = (Bencodex.Types.List)value; return(goldDistributions.Select(v => new GoldDistribution(v))); } catch (Exception e) { Log.Error(e, $"Unexpected error occurred during {nameof(GetGoldDistribution)}()"); throw; } }
public static IAccountStateDelta MarkBalanceChanged( this IAccountStateDelta states, Currency currency, params Address[] accounts ) { if (accounts.Length == 1) { return(states.MintAsset(accounts[0], currency * 1)); } else if (accounts.Length < 1) { return(states); } for (int i = 1; i < accounts.Length; i++) { states = states.TransferAsset(accounts[i - 1], accounts[i], currency * 1, true); } return(states); }
public void ExecuteThrowSheetRowNotFoundException() { var row = _tableSheets.EquipmentItemRecipeSheet.Values.First(); var materialRow = _tableSheets.MaterialItemSheet[row.MaterialId]; var material = ItemFactory.CreateItem(materialRow, _random); _avatarState.inventory.AddItem(material, row.MaterialCount); const int requiredStage = GameConfig.RequireClearedStageLevel.CombinationEquipmentAction; for (var i = 1; i < requiredStage + 1; i++) { _avatarState.worldInformation.ClearStage( 1, i, 0, _tableSheets.WorldSheet, _tableSheets.WorldUnlockSheet ); } _initialState = _initialState.SetState(_avatarAddress, _avatarState.Serialize()); var action = new CombinationEquipment() { AvatarAddress = _avatarAddress, RecipeId = 999, SlotIndex = 0, }; Assert.Throws <SheetRowNotFoundException>(() => action.Execute(new ActionContext() { PreviousStates = _initialState, Signer = _agentAddress, BlockIndex = 1, Random = _random, }) ); }
public void Execute() { var privateKey = new PrivateKey(); PublicKey publicKey = privateKey.PublicKey; var prevRedeemCodesState = new RedeemCodeState(new Dictionary <PublicKey, Reward>() { [publicKey] = new Reward(1), }); var gameConfigState = new GameConfigState(); var agentState = new AgentState(_agentAddress); agentState.avatarAddresses[0] = _avatarAddress; var avatarState = new AvatarState( _avatarAddress, _agentAddress, 1, _tableSheets, gameConfigState ); var goldState = new GoldCurrencyState(new Currency("NCG", 2, minter: null)); var initialState = new State() .SetState(_agentAddress, agentState.Serialize()) .SetState(_avatarAddress, avatarState.Serialize()) .SetState(TableSheetsState.Address, _tableSheetsState.Serialize()) .SetState(RedeemCodeState.Address, prevRedeemCodesState.Serialize()) .SetState(GoldCurrencyState.Address, goldState.Serialize()) .MintAsset(GoldCurrencyState.Address, goldState.Currency * 100000000); var redeemCode = new RedeemCode( ByteUtil.Hex(privateKey.ByteArray), _avatarAddress ); IAccountStateDelta nextState = redeemCode.Execute(new ActionContext() { BlockIndex = 1, Miner = default,
public override IAccountStateDelta Execute(IActionContext context) { IAccountStateDelta state = context.PreviousStates; if (context.Rehearsal) { return(state .SetState(ActivatedAccountsState.Address, MarkChanged) .SetState(PendingAddress, MarkChanged)); } if (!state.TryGetState(ActivatedAccountsState.Address, out Dictionary accountsAsDict)) { throw new ActivatedAccountsDoesNotExistsException(); } if (!state.TryGetState(PendingAddress, out Dictionary pendingAsDict)) { throw new PendingActivationDoesNotExistsException(PendingAddress); } var accounts = new ActivatedAccountsState(accountsAsDict); var pending = new PendingActivationState(pendingAsDict); if (pending.Verify(this)) { return(state.SetState( ActivatedAccountsState.Address, accounts.AddAccount(context.Signer).Serialize() ).SetState( pending.address, new Bencodex.Types.Null() )); } else { throw new InvalidSignatureException(pending, Signature); } }
internal ActionEvaluation EvaluateBlockAction( Block <T> block, IReadOnlyList <ActionEvaluation> txActionEvaluations) { if (Policy.BlockAction is null) { var message = "To evaluate block action, Policy.BlockAction must not be null."; throw new InvalidOperationException(message); } _logger.Debug( "Evaluating block action in block {blockIndex}: {block}", block?.Index, block); IAccountStateDelta lastStates = null; if (!(txActionEvaluations is null) && txActionEvaluations.Count > 0) { lastStates = txActionEvaluations[txActionEvaluations.Count - 1].OutputStates; } Address miner = block.Miner.GetValueOrDefault(); if (lastStates is null) { lastStates = new AccountStateDeltaImpl( a => GetState(a, block.PreviousHash).GetValueOrDefault(a)); } return(ActionEvaluation.EvaluateActionsGradually( block.Hash, block.Index, null, lastStates, miner, miner, Array.Empty <byte>(), new[] { Policy.BlockAction }.ToImmutableList()).First()); }
public void Rehearsal() { Address collectionAddress = MonsterCollectionState0.DeriveAddress(_signer, 1); MonsterCollect0 action = new MonsterCollect0 { level = 1, collectionRound = 1, }; IAccountStateDelta nextState = action.Execute(new ActionContext { PreviousStates = new State(), Signer = _signer, Rehearsal = true, }); List <Address> updatedAddresses = new List <Address>() { _signer, collectionAddress, }; Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.UpdatedAddresses); }
public static bool TryGetAgentAvatarStates( this IAccountStateDelta states, Address agentAddress, Address avatarAddress, out AgentState agentState, out AvatarState avatarState ) { avatarState = null; agentState = states.GetAgentState(agentAddress); if (agentState is null) { return(false); } if (!agentState.avatarAddresses.ContainsValue(avatarAddress)) { throw new AgentStateNotContainsAvatarAddressException( $"The avatar {avatarAddress.ToHex()} does not belong to the agent {agentAddress.ToHex()}."); } avatarState = states.GetAvatarState(avatarAddress); return(!(avatarState is null)); }
public override IAccountStateDelta Execute(IActionContext context) { IAccountStateDelta state = context.PreviousStates; Address activatedAddress = context.Signer.Derive(ActivationKey.DeriveKey); if (context.Rehearsal) { return(state .SetState(activatedAddress, MarkChanged) .SetState(PendingAddress, MarkChanged)); } if (!(state.GetState(activatedAddress) is null)) { throw new AlreadyActivatedException($"{context.Signer} already activated."); } if (!state.TryGetState(PendingAddress, out Dictionary pendingAsDict)) { throw new PendingActivationDoesNotExistsException(PendingAddress); } var pending = new PendingActivationState(pendingAsDict); if (pending.Verify(this)) { // We left this log message to track activation history. // Please delete it if we have an API for evaluation results on the Libplanet side. Log.Information("{pendingAddress} is activated by {signer} now.", pending.address, context.Signer); return(state .SetState(activatedAddress, true.Serialize()) .SetState(pending.address, new Bencodex.Types.Null())); } else { throw new InvalidSignatureException(pending, Signature); } }
public static bool TryGetAvatarStateV2( this IAccountStateDelta states, Address agentAddress, Address avatarAddress, out AvatarState avatarState, out bool migrationRequired ) { avatarState = null; migrationRequired = false; if (states.GetState(avatarAddress) is Dictionary serializedAvatar) { try { if (serializedAvatar[AgentAddressKey].ToAddress() != agentAddress) { return(false); } avatarState = GetAvatarStateV2(states, avatarAddress); return(true); } catch (Exception e) { // BackWardCompatible. if (e is KeyNotFoundException || e is FailedLoadStateException) { migrationRequired = true; return(states.TryGetAvatarState(agentAddress, avatarAddress, out avatarState)); } return(false); } } return(false); }