public override IAccountStateDelta Execute(IActionContext context) { var states = context.PreviousStates; var slotAddress = avatarAddress.Derive( string.Format( CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, slotIndex ) ); if (context.Rehearsal) { return(states .SetState(avatarAddress, MarkChanged) .SetState(slotAddress, MarkChanged)); } CheckObsolete(BlockChain.Policy.BlockPolicySource.V100080ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); if (!states.TryGetAgentAvatarStates( context.Signer, avatarAddress, out var agentState, out var avatarState)) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load."); } var slotState = states.GetCombinationSlotState(avatarAddress, slotIndex); if (slotState?.Result is null) { throw new CombinationSlotResultNullException($"{addressesHex}CombinationSlot Result is null. ({avatarAddress}), ({slotIndex})"); } if (!avatarState.worldInformation.IsStageCleared(slotState.UnlockStage)) { avatarState.worldInformation.TryGetLastClearedStageId(out var current); throw new NotEnoughClearedStageLevelException(addressesHex, slotState.UnlockStage, current); } var diff = slotState.Result.itemUsable.RequiredBlockIndex - context.BlockIndex; if (diff <= 0) { throw new RequiredBlockIndexException($"{addressesHex}Already met the required block index. context block index: {context.BlockIndex}, required block index: {slotState.Result.itemUsable.RequiredBlockIndex}"); } var gameConfigState = states.GetGameConfigState(); if (gameConfigState is null) { throw new FailedLoadStateException($"{addressesHex}Aborted as the GameConfigState was failed to load."); } var count = RapidCombination0.CalculateHourglassCount(gameConfigState, diff); var materialItemSheet = states.GetSheet <MaterialItemSheet>(); var row = materialItemSheet.Values.First(r => r.ItemSubType == ItemSubType.Hourglass); var hourGlass = ItemFactory.CreateMaterial(row); if (!avatarState.inventory.RemoveFungibleItem2(hourGlass, count)) { throw new NotEnoughMaterialException( $"{addressesHex}Aborted as the player has no enough material ({row.Id} * {count})"); } slotState.Update(context.BlockIndex, hourGlass, count); avatarState.UpdateFromRapidCombination( (CombinationConsumable5.ResultModel)slotState.Result, context.BlockIndex ); return(states .SetState(avatarAddress, avatarState.Serialize()) .SetState(slotAddress, slotState.Serialize())); }
public override IAccountStateDelta Execute(IActionContext context) { var states = context.PreviousStates; var slotAddress = avatarAddress.Derive( string.Format( CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, slotIndex ) ); var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); if (context.Rehearsal) { return(states .SetState(avatarAddress, MarkChanged) .SetState(inventoryAddress, MarkChanged) .SetState(worldInformationAddress, MarkChanged) .SetState(questListAddress, MarkChanged) .SetState(slotAddress, MarkChanged)); } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); if (!states.TryGetAgentAvatarStatesV2( context.Signer, avatarAddress, out var agentState, out var avatarState)) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load."); } var slotState = states.GetCombinationSlotState(avatarAddress, slotIndex); if (slotState?.Result is null) { throw new CombinationSlotResultNullException($"{addressesHex}CombinationSlot Result is null. ({avatarAddress}), ({slotIndex})"); } if (!avatarState.worldInformation.IsStageCleared(slotState.UnlockStage)) { avatarState.worldInformation.TryGetLastClearedStageId(out var current); throw new NotEnoughClearedStageLevelException(addressesHex, slotState.UnlockStage, current); } var diff = slotState.Result.itemUsable.RequiredBlockIndex - context.BlockIndex; if (diff <= 0) { throw new RequiredBlockIndexException($"{addressesHex}Already met the required block index. context block index: {context.BlockIndex}, required block index: {slotState.Result.itemUsable.RequiredBlockIndex}"); } var gameConfigState = states.GetGameConfigState(); if (gameConfigState is null) { throw new FailedLoadStateException($"{addressesHex}Aborted as the GameConfigState was failed to load."); } if (context.BlockIndex < slotState.StartBlockIndex + GameConfig.RequiredAppraiseBlock) { throw new AppraiseBlockNotReachedException( $"{addressesHex}Aborted as Item appraisal block section. " + $"context block index: {context.BlockIndex}, " + $"actionable block index : {slotState.StartBlockIndex + GameConfig.RequiredAppraiseBlock}"); } var count = RapidCombination0.CalculateHourglassCount(gameConfigState, diff); var materialItemSheet = states.GetSheet <MaterialItemSheet>(); var row = materialItemSheet.Values.First(r => r.ItemSubType == ItemSubType.Hourglass); var hourGlass = ItemFactory.CreateMaterial(row); if (!avatarState.inventory.RemoveFungibleItem(hourGlass, context.BlockIndex, count)) { throw new NotEnoughMaterialException( $"{addressesHex}Aborted as the player has no enough material ({row.Id} * {count})"); } if (slotState.TryGetResultId(out var resultId) && avatarState.mailBox.All(mail => mail.id != resultId) && slotState.TryGetMail( context.BlockIndex, context.BlockIndex, out var combinationMail, out var itemEnhanceMail)) { if (combinationMail != null) { avatarState.Update(combinationMail); } else if (itemEnhanceMail != null) { avatarState.Update(itemEnhanceMail); } } slotState.UpdateV2(context.BlockIndex, hourGlass, count); avatarState.UpdateFromRapidCombinationV2( (RapidCombination5.ResultModel)slotState.Result, context.BlockIndex); return(states .SetState(avatarAddress, avatarState.SerializeV2()) .SetState(inventoryAddress, avatarState.inventory.Serialize()) .SetState(worldInformationAddress, avatarState.worldInformation.Serialize()) .SetState(questListAddress, avatarState.questList.Serialize()) .SetState(slotAddress, slotState.Serialize())); }