public override void Render(IActionContext context, IAccountStateDelta nextStates) { GameState gameState; if (nextStates.TryGetState(SessionState.Address, out Bencodex.Types.Dictionary bdict)) { var sessionState = new SessionState(bdict); sessionState.sessions.TryGetValue(SessionID, out gameState); } else { Debug.LogError("SessionState is empty on render."); return; } if (gameState is null) { Debug.LogError("GameState is null on rendering."); return; } if (gameState.SessionID == GameManager.instance.currentSession) { Agent.instance.RunOnMainThread(() => { GameManager.instance.gameboard?.PlaceNode(false, gameState.Turn, Index); GameManager.instance.SetMyTurn(gameState.Turn == gameState.Players.IndexOf(Agent.instance.Address)); GameManager.instance.gameboard.UpdateInfo(); }); } }
public override IAccountStateDelta Execute(IActionContext context) { IAccountStateDelta state = context.PreviousStates; if (context.Rehearsal) { return(state .SetState(ActivatedAccountsState.Address, MarkChanged)); } if (!state.TryGetState(ActivatedAccountsState.Address, out Dictionary accountsAsDict)) { throw new ActivatedAccountsDoesNotExistsException(); } CheckObsolete(BlockChain.Policy.BlockPolicySource.V100080ObsoleteIndex, context); CheckPermission(context); var accounts = new ActivatedAccountsState(accountsAsDict); return(state.SetState( ActivatedAccountsState.Address, accounts.AddAccount(Address).Serialize() )); }
public override void Render(IActionContext context, IAccountStateDelta nextStates) { GameState gameState; if (nextStates.TryGetState(SessionState.Address, out Bencodex.Types.Dictionary bdict)) { var sessionState = new SessionState(bdict); sessionState.sessions.TryGetValue(SessionID, out gameState); } else { Debug.LogError("SessionState is empty on render."); return; } if (gameState is null) { Debug.LogError("GameState is null on rendering."); return; } if (gameState.SessionID == GameManager.instance.currentSession) { Agent.instance.RunOnMainThread(() => { Debug.LogWarning("Render Resign Action"); GameManager.instance.gameboard?.SetResult(gameState.Winner == Agent.instance.Address); }); } }
public override IAccountStateDelta Execute(IActionContext context) { IAccountStateDelta state = context.PreviousStates; if (context.Rehearsal) { return(state .SetState(ActivatedAccountsState.Address, MarkChanged) .SetState(PendingAddress, MarkChanged)); } CheckObsolete(BlockChain.Policy.BlockPolicySource.V100080ObsoleteIndex, context); 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(Signature)) { // 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( ActivatedAccountsState.Address, accounts.AddAccount(context.Signer).Serialize() ).SetState( pending.address, new Bencodex.Types.Null() )); } else { throw new InvalidSignatureException(pending, Signature); } }
public override IAccountStateDelta Execute(IActionContext context) { IAccountStateDelta states = context.PreviousStates; Address collectionAddress = MonsterCollectionState0.DeriveAddress(context.Signer, collectRound); if (context.Rehearsal) { return(states .SetState(collectionAddress, MarkChanged) .MarkBalanceChanged(GoldCurrencyMock, collectionAddress, context.Signer)); } CheckObsolete(BlockChain.Policy.BlockPolicySource.V100080ObsoleteIndex, context); AgentState agentState = states.GetAgentState(context.Signer); if (agentState is null) { throw new FailedLoadStateException("Aborted as the agent state failed to load."); } if (!states.TryGetState(collectionAddress, out Dictionary stateDict)) { throw new FailedLoadStateException($"Aborted as the monster collection state failed to load."); } MonsterCollectionState0 monsterCollectionState = new MonsterCollectionState0(stateDict); Currency currency = states.GetGoldCurrency(); FungibleAssetValue balance = 0 * currency; MonsterCollectionSheet monsterCollectionSheet = states.GetSheet <MonsterCollectionSheet>(); int currentLevel = monsterCollectionState.Level; if (currentLevel <= level || level <= 0) { throw new InvalidLevelException($"The level must be greater than 0 and less than {currentLevel}."); } if (monsterCollectionState.End) { throw new MonsterCollectionExpiredException($"{collectionAddress} has already expired on {monsterCollectionState.ExpiredBlockIndex}"); } long rewardLevel = monsterCollectionState.GetRewardLevel(context.BlockIndex); MonsterCollectionRewardSheet monsterCollectionRewardSheet = states.GetSheet <MonsterCollectionRewardSheet>(); monsterCollectionState.Update(level, rewardLevel, monsterCollectionRewardSheet); for (int i = currentLevel; i > level; i--) { balance += monsterCollectionSheet[i].RequiredGold * currency; } return(states .SetState(collectionAddress, monsterCollectionState.Serialize()) .TransferAsset(collectionAddress, context.Signer, balance)); }
public static Currency GetGoldCurrency(this IAccountStateDelta states) { if (states.TryGetState(GoldCurrencyState.Address, out Dictionary asDict)) { return(new GoldCurrencyState(asDict).Currency); } throw new InvalidOperationException( "The states doesn't contain gold currency.\n" + "Check the genesis block." ); }
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 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); } }
public override void Render(IActionContext context, IAccountStateDelta nextStates) { SessionState sessionState; if (nextStates.TryGetState(SessionState.Address, out Bencodex.Types.Dictionary bdict)) { sessionState = new SessionState(bdict); } else { sessionState = new SessionState(); } Agent.instance.RunOnMainThread(() => { GameManager.instance.sessionUI?.UpdateUI(sessionState, SessionID); }); }
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 void TargetBlock() { var rb = new RankingBattle { avatarAddress = _avatar1Address, enemyAddress = _avatar3Address, weeklyArenaAddress = _weeklyArenaAddress, costumeIds = new List <Guid>(), equipmentIds = new List <Guid>(), }; var arenaInfoAddress = _weeklyArenaAddress.Derive(_avatar1Address.ToByteArray()); var arenaInfo2Address = _weeklyArenaAddress.Derive(_avatar2Address.ToByteArray()); var arenaInfo3Address = _weeklyArenaAddress.Derive(_avatar3Address.ToByteArray()); var listAddress = _weeklyArenaAddress.Derive("address_list"); Assert.False(_initialState.TryGetState(arenaInfoAddress, out Dictionary _)); Assert.False(_initialState.TryGetState(arenaInfo2Address, out Dictionary _)); Assert.False(_initialState.TryGetState(arenaInfo3Address, out Dictionary _)); Assert.False(_initialState.TryGetState(listAddress, out List _)); var testRandom = new TestRandom(); var blockIndex = RankingBattle.UpdateTargetBlockIndex; var nextState = rb.Execute(new ActionContext { PreviousStates = _initialState, Signer = _agent1Address, Random = testRandom, Rehearsal = false, BlockIndex = blockIndex, }); Assert.True(nextState.TryGetState(arenaInfoAddress, out Dictionary rawInfo)); Assert.True(nextState.TryGetState(arenaInfo3Address, out Dictionary _)); Assert.True(nextState.TryGetState(listAddress, out List rawList)); var info = new ArenaInfo(rawInfo); var addressList = rawList.ToList(StateExtensions.ToAddress); Assert.Equal(4, info.DailyChallengeCount); Assert.Contains(_avatar1Address, addressList); Assert.DoesNotContain(_avatar2Address, addressList); Assert.Contains(_avatar3Address, addressList); var rg = new RewardGold(); var updatedState = rg.Execute(new ActionContext { PreviousStates = nextState, Signer = _agent1Address, Random = testRandom, Rehearsal = false, BlockIndex = blockIndex, }); Assert.True(updatedState.TryGetState(arenaInfoAddress, out Dictionary updatedRawInfo)); Assert.True(updatedState.TryGetState(arenaInfo2Address, out Dictionary _)); Assert.True(updatedState.TryGetState(arenaInfo3Address, out Dictionary _)); Assert.True(updatedState.TryGetState(listAddress, out List updatedRawList)); var updatedInfo = new ArenaInfo(updatedRawInfo); var updatedAddressList = updatedRawList.ToList(StateExtensions.ToAddress); Assert.Equal(5, updatedInfo.DailyChallengeCount); Assert.Contains(_avatar1Address, updatedAddressList); Assert.Contains(_avatar2Address, updatedAddressList); Assert.Contains(_avatar3Address, updatedAddressList); }
public override IAccountStateDelta Execute(IActionContext context) { IAccountStateDelta states = context.PreviousStates; Address inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); Address worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); Address questListAddress = avatarAddress.Derive(LegacyQuestListKey); if (context.Rehearsal) { return(states .SetState(avatarAddress, MarkChanged) .SetState(inventoryAddress, MarkChanged) .SetState(worldInformationAddress, MarkChanged) .SetState(questListAddress, MarkChanged) .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 0), MarkChanged) .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 1), MarkChanged) .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 2), MarkChanged) .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 3), MarkChanged)); } CheckObsolete(BlockChain.Policy.BlockPolicySource.V100080ObsoleteIndex, context); if (!states.TryGetAgentAvatarStatesV2(context.Signer, avatarAddress, out AgentState agentState, out AvatarState avatarState)) { throw new FailedLoadStateException($"Aborted as the avatar state of the signer failed to load."); } Address collectionAddress = MonsterCollectionState.DeriveAddress(context.Signer, agentState.MonsterCollectionRound); if (!states.TryGetState(collectionAddress, out Dictionary stateDict)) { throw new FailedLoadStateException($"Aborted as the monster collection state failed to load."); } var monsterCollectionState = new MonsterCollectionState(stateDict); List <MonsterCollectionRewardSheet.RewardInfo> rewards = monsterCollectionState.CalculateRewards( states.GetSheet <MonsterCollectionRewardSheet>(), context.BlockIndex ); if (rewards.Count == 0) { throw new RequiredBlockIndexException($"{collectionAddress} is not available yet"); } Guid id = context.Random.GenerateRandomGuid(); var result = new MonsterCollectionResult(id, avatarAddress, rewards); var mail = new MonsterCollectionMail(result, context.BlockIndex, id, context.BlockIndex); avatarState.Update(mail); ItemSheet itemSheet = states.GetItemSheet(); foreach (MonsterCollectionRewardSheet.RewardInfo rewardInfo in rewards) { ItemSheet.Row row = itemSheet[rewardInfo.ItemId]; ItemBase item = row is MaterialItemSheet.Row materialRow ? ItemFactory.CreateTradableMaterial(materialRow) : ItemFactory.CreateItem(row, context.Random); avatarState.inventory.AddItem2(item, rewardInfo.Quantity); } monsterCollectionState.Claim(context.BlockIndex); return(states .SetState(avatarAddress, avatarState.SerializeV2()) .SetState(inventoryAddress, avatarState.inventory.Serialize()) .SetState(worldInformationAddress, avatarState.worldInformation.Serialize()) .SetState(questListAddress, avatarState.questList.Serialize()) .SetState(collectionAddress, monsterCollectionState.Serialize())); }
public override IAccountStateDelta Execute(IActionContext context) { IAccountStateDelta states = context.PreviousStates; Address monsterCollectionAddress = MonsterCollectionState0.DeriveAddress(context.Signer, collectionRound); if (context.Rehearsal) { return(states .SetState(monsterCollectionAddress, MarkChanged) .SetState(context.Signer, MarkChanged) .MarkBalanceChanged(GoldCurrencyMock, context.Signer, monsterCollectionAddress)); } CheckObsolete(BlockChain.Policy.BlockPolicySource.V100080ObsoleteIndex, context); MonsterCollectionSheet monsterCollectionSheet = states.GetSheet <MonsterCollectionSheet>(); AgentState agentState = states.GetAgentState(context.Signer); if (agentState is null) { throw new FailedLoadStateException("Aborted as the agent state failed to load."); } if (agentState.MonsterCollectionRound != collectionRound) { throw new InvalidMonsterCollectionRoundException( $"Expected collection round is {agentState.MonsterCollectionRound}, but actual collection round is {collectionRound}."); } if (!monsterCollectionSheet.TryGetValue(level, out MonsterCollectionSheet.Row _)) { throw new SheetRowNotFoundException(nameof(MonsterCollectionSheet), level); } Currency currency = states.GetGoldCurrency(); // Set default gold value. FungibleAssetValue requiredGold = currency * 0; FungibleAssetValue balance = states.GetBalance(context.Signer, states.GetGoldCurrency()); MonsterCollectionState0 monsterCollectionState; int currentLevel = 1; MonsterCollectionRewardSheet monsterCollectionRewardSheet = states.GetSheet <MonsterCollectionRewardSheet>(); if (states.TryGetState(monsterCollectionAddress, out Dictionary stateDict)) { monsterCollectionState = new MonsterCollectionState0(stateDict); if (monsterCollectionState.ExpiredBlockIndex < context.BlockIndex) { throw new MonsterCollectionExpiredException( $"{monsterCollectionAddress} has already expired on {monsterCollectionState.ExpiredBlockIndex}"); } if (monsterCollectionState.Level >= level) { throw new InvalidLevelException($"The level must be greater than {monsterCollectionState.Level}."); } currentLevel = monsterCollectionState.Level + 1; long rewardLevel = monsterCollectionState.GetRewardLevel(context.BlockIndex); monsterCollectionState.Update(level, rewardLevel, monsterCollectionRewardSheet); } else { monsterCollectionState = new MonsterCollectionState0(monsterCollectionAddress, level, context.BlockIndex, monsterCollectionRewardSheet); } for (int i = currentLevel; i < level + 1; i++) { requiredGold += currency * monsterCollectionSheet[i].RequiredGold; } if (balance < requiredGold) { throw new InsufficientBalanceException(context.Signer, requiredGold, $"There is no sufficient balance for {context.Signer}: {balance} < {requiredGold}"); } states = states.TransferAsset(context.Signer, monsterCollectionAddress, requiredGold); states = states.SetState(monsterCollectionAddress, monsterCollectionState.Serialize()); return(states); }
public override IAccountStateDelta Execute(IActionContext context) { IAccountStateDelta states = context.PreviousStates; if (context.Rehearsal) { return(states .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 0), MarkChanged) .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 1), MarkChanged) .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 2), MarkChanged) .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 3), MarkChanged) .SetState(context.Signer, MarkChanged) .MarkBalanceChanged(GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 0)) .MarkBalanceChanged(GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 1)) .MarkBalanceChanged(GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 2)) .MarkBalanceChanged(GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 3))); } MonsterCollectionSheet monsterCollectionSheet = states.GetSheet <MonsterCollectionSheet>(); AgentState agentState = states.GetAgentState(context.Signer); if (agentState is null) { throw new FailedLoadStateException("Aborted as the agent state failed to load."); } if (level < 0 || level > 0 && !monsterCollectionSheet.TryGetValue(level, out MonsterCollectionSheet.Row _)) { throw new MonsterCollectionLevelException(); } Currency currency = states.GetGoldCurrency(); // Set default gold value. FungibleAssetValue requiredGold = currency * 0; Address monsterCollectionAddress = MonsterCollectionState.DeriveAddress( context.Signer, agentState.MonsterCollectionRound ); if (states.TryGetState(monsterCollectionAddress, out Dictionary stateDict)) { var existingStates = new MonsterCollectionState(stateDict); int previousLevel = existingStates.Level; // Check collection level and required block index if (level < previousLevel && existingStates.IsLocked(context.BlockIndex)) { throw new RequiredBlockIndexException(); } if (level == previousLevel) { throw new MonsterCollectionLevelException(); } if (existingStates.CalculateStep(context.BlockIndex) > 0) { throw new MonsterCollectionExistingClaimableException(); } // Refund holding NCG to user FungibleAssetValue gold = states.GetBalance(monsterCollectionAddress, currency); states = states.TransferAsset(monsterCollectionAddress, context.Signer, gold); } if (level == 0) { return(states.SetState(monsterCollectionAddress, new Null())); } FungibleAssetValue balance = states.GetBalance(context.Signer, currency); var monsterCollectionState = new MonsterCollectionState(monsterCollectionAddress, level, context.BlockIndex); for (int i = 0; i < level; i++) { requiredGold += currency * monsterCollectionSheet[i + 1].RequiredGold; } if (balance < requiredGold) { throw new InsufficientBalanceException(context.Signer, requiredGold, $"There is no sufficient balance for {context.Signer}: {balance} < {requiredGold}"); } states = states.TransferAsset(context.Signer, monsterCollectionAddress, requiredGold); states = states.SetState(monsterCollectionAddress, monsterCollectionState.Serialize()); return(states); }
public IAccountStateDelta PrepareNextArena(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()); } // 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); var listAddress = weekly.address.Derive("address_list"); // Set ArenaInfo, address list for new RankingBattle. var addressList = states.TryGetState(listAddress, out List rawList) ? rawList.ToList(StateExtensions.ToAddress) : new List <Address>(); if (ctx.BlockIndex >= RankingBattle.UpdateTargetBlockIndex) { weekly.ResetIndex = ctx.BlockIndex; // Copy Map to address list. if (ctx.BlockIndex == RankingBattle.UpdateTargetBlockIndex) { foreach (var kv in prevWeekly.Map) { var address = kv.Key; var lazyInfo = kv.Value; var info = new ArenaInfo(lazyInfo.State); states = states.SetState( weeklyAddress.Derive(address.ToByteArray()), info.Serialize()); if (!addressList.Contains(address)) { addressList.Add(address); } } } else { // Copy addresses from prev weekly address list. var prevListAddress = prevWeekly.address.Derive("address_list"); if (states.TryGetState(prevListAddress, out List prevRawList)) { var prevList = prevRawList.ToList(StateExtensions.ToAddress); foreach (var address in prevList.Where(address => !addressList.Contains(address))) { addressList.Add(address); } } // Copy ArenaInfo from prev ArenaInfo. foreach (var address in addressList) { if (states.TryGetState( prevWeekly.address.Derive(address.ToByteArray()), out Dictionary rawInfo)) { var prevInfo = new ArenaInfo(rawInfo); var info = new ArenaInfo(prevInfo); states = states.SetState( weeklyAddress.Derive(address.ToByteArray()), info.Serialize()); } } } // Set address list. states = states.SetState(listAddress, addressList.Aggregate(List.Empty, (current, address) => current.Add(address.Serialize()))); } // Run legacy Update. else { weekly.Update(prevWeekly, ctx.BlockIndex); } states = states.SetState(prevWeeklyAddress, rawPrevWeekly); states = states.SetState(weeklyAddress, weekly.Serialize()); } } return(states); }
public override IAccountStateDelta Execute(IActionContext context) { IAccountStateDelta states = context.PreviousStates; Address collectionAddress = MonsterCollectionState0.DeriveAddress(context.Signer, collectionRound); if (context.Rehearsal) { return(states .SetState(context.Signer, MarkChanged) .SetState(avatarAddress, MarkChanged) .SetState(collectionAddress, MarkChanged)); } CheckObsolete(BlockChain.Policy.BlockPolicySource.V100080ObsoleteIndex, context); if (!states.TryGetAgentAvatarStates(context.Signer, avatarAddress, out AgentState agentState, out AvatarState avatarState)) { throw new FailedLoadStateException($"Aborted as the avatar state of the signer failed to load."); } if (!states.TryGetState(collectionAddress, out Dictionary stateDict)) { throw new FailedLoadStateException($"Aborted as the monster collection state failed to load."); } MonsterCollectionState0 monsterCollectionState = new MonsterCollectionState0(stateDict); if (monsterCollectionState.End) { throw new MonsterCollectionExpiredException($"{collectionAddress} has already expired on {monsterCollectionState.ExpiredBlockIndex}"); } if (!monsterCollectionState.CanReceive(context.BlockIndex)) { throw new RequiredBlockIndexException( $"{collectionAddress} is not available yet; it will be available after {Math.Max(monsterCollectionState.StartedBlockIndex, monsterCollectionState.ReceivedBlockIndex) + MonsterCollectionState0.RewardInterval}"); } long rewardLevel = monsterCollectionState.GetRewardLevel(context.BlockIndex); ItemSheet itemSheet = states.GetItemSheet(); for (int i = 0; i < rewardLevel; i++) { int level = i + 1; if (level <= monsterCollectionState.RewardLevel) { continue; } List <MonsterCollectionRewardSheet.RewardInfo> rewards = monsterCollectionState.RewardLevelMap[level]; Guid id = context.Random.GenerateRandomGuid(); MonsterCollectionResult result = new MonsterCollectionResult(id, avatarAddress, rewards); MonsterCollectionMail mail = new MonsterCollectionMail(result, context.BlockIndex, id, context.BlockIndex); avatarState.Update(mail); foreach (var rewardInfo in rewards) { var row = itemSheet[rewardInfo.ItemId]; var item = row is MaterialItemSheet.Row materialRow ? ItemFactory.CreateTradableMaterial(materialRow) : ItemFactory.CreateItem(row, context.Random); avatarState.inventory.AddItem2(item, rewardInfo.Quantity); } monsterCollectionState.UpdateRewardMap(level, result, context.BlockIndex); } // Return gold at the end of monster collect. if (rewardLevel == 4) { MonsterCollectionSheet monsterCollectionSheet = states.GetSheet <MonsterCollectionSheet>(); Currency currency = states.GetGoldCurrency(); // Set default gold value. FungibleAssetValue gold = currency * 0; for (int i = 0; i < monsterCollectionState.Level; i++) { int level = i + 1; gold += currency * monsterCollectionSheet[level].RequiredGold; } agentState.IncreaseCollectionRound(); states = states.SetState(context.Signer, agentState.Serialize()); if (gold > currency * 0) { states = states.TransferAsset(collectionAddress, context.Signer, gold); } } return(states .SetState(avatarAddress, avatarState.Serialize()) .SetState(collectionAddress, monsterCollectionState.Serialize())); }