public void SerializeCombinationSlotStateWithResult() { var address = new PrivateKey().PublicKey.ToAddress(); var state = new CombinationSlotState(address, 1); var item = ItemFactory.CreateItemUsable(_tableSheets.EquipmentItemSheet.Values.First(), Guid.Empty, default); var result = new CombinationConsumable.ResultModel { actionPoint = 1, gold = 1, materials = new Dictionary <Nekoyume.Model.Item.Material, int>(), itemUsable = item }; state.Update(result, 1, 10); var serialized = (Dictionary)state.Serialize(); Assert.IsTrue(serialized.ContainsKey((IKey)(Text)"address")); Assert.IsTrue(serialized.ContainsKey((IKey)(Text)"unlockBlockIndex")); Assert.IsTrue(serialized.ContainsKey((IKey)(Text)"unlockStage")); Assert.IsTrue(serialized.ContainsKey((IKey)(Text)"result")); Assert.IsTrue(serialized.ContainsKey((IKey)(Text)"startBlockIndex")); var deserialize = new CombinationSlotState(serialized); Assert.AreEqual(state.UnlockStage, deserialize.UnlockStage); Assert.AreEqual(state.UnlockBlockIndex, deserialize.UnlockBlockIndex); Assert.AreEqual(state.address, deserialize.address); Assert.AreEqual(state.Result.itemUsable, deserialize.Result.itemUsable); Assert.AreEqual(state.StartBlockIndex, deserialize.StartBlockIndex); }
public void SetCombinationSlotState(CombinationSlotState state) { state = LocalLayer.Instance.Modify(state); CombinationSlotStates[state.address] = state; CombinationSlotStateSubject.OnNext(state); }
public static bool TryGetResultId(this CombinationSlotState state, out Guid resultId) { if (state?.Result is null) { return(false); } switch (state.Result) { case Buy7.BuyerResult r: resultId = r.id; break; case Buy7.SellerResult r: resultId = r.id; break; case DailyReward2.DailyRewardResult r: resultId = r.id; break; case ItemEnhancement.ResultModel r: resultId = r.id; break; case ItemEnhancement7.ResultModel r: resultId = r.id; break; case MonsterCollectionResult r: resultId = r.id; break; case CombinationConsumable5.ResultModel r: resultId = r.id; break; case RapidCombination5.ResultModel r: resultId = r.id; break; case SellCancellation.Result r: resultId = r.id; break; case SellCancellation7.Result r: resultId = r.id; break; case SellCancellation8.Result r: resultId = r.id; break; default: return(false); } return(true); }
public void CombinationSlotState() { var address = new PrivateKey().PublicKey.ToAddress(); var state = new CombinationSlotState(address, 1); Assert.AreEqual(address, state.address); Assert.AreEqual(1, state.UnlockStage); Assert.AreEqual(0, state.UnlockBlockIndex); }
public static void ResetCombinationSlot(CombinationSlotState slot) { LocalLayer.Instance .ResetCombinationSlotModifiers <CombinationSlotBlockIndexModifier>( slot.address); LocalLayer.Instance .ResetCombinationSlotModifiers <CombinationSlotBlockIndexAndResultModifier>( slot.address); }
public HackAndSlash10Test() { _sheets = TableSheetsImporter.ImportSheets(); _tableSheets = new TableSheets(_sheets); var privateKey = new PrivateKey(); _agentAddress = privateKey.PublicKey.ToAddress(); var agentState = new AgentState(_agentAddress); _avatarAddress = _agentAddress.Derive("avatar"); var gameConfigState = new GameConfigState(_sheets[nameof(GameConfigSheet)]); _rankingMapAddress = _avatarAddress.Derive("ranking_map"); _avatarState = new AvatarState( _avatarAddress, _agentAddress, 0, _tableSheets.GetAvatarSheets(), gameConfigState, _rankingMapAddress ) { level = 100, }; _inventoryAddress = _avatarAddress.Derive(LegacyInventoryKey); _worldInformationAddress = _avatarAddress.Derive(LegacyWorldInformationKey); _questListAddress = _avatarAddress.Derive(LegacyQuestListKey); agentState.avatarAddresses.Add(0, _avatarAddress); _weeklyArenaState = new WeeklyArenaState(0); _initialState = new State() .SetState(_weeklyArenaState.address, _weeklyArenaState.Serialize()) .SetState(_agentAddress, agentState.SerializeV2()) .SetState(_avatarAddress, _avatarState.SerializeV2()) .SetState(_inventoryAddress, _avatarState.inventory.Serialize()) .SetState(_worldInformationAddress, _avatarState.worldInformation.Serialize()) .SetState(_questListAddress, _avatarState.questList.Serialize()) .SetState(_rankingMapAddress, new RankingMapState(_rankingMapAddress).Serialize()) .SetState(gameConfigState.address, gameConfigState.Serialize()); foreach (var(key, value) in _sheets) { _initialState = _initialState .SetState(Addresses.TableSheet.Derive(key), value.Serialize()); } foreach (var address in _avatarState.combinationSlotAddresses) { var slotState = new CombinationSlotState( address, GameConfig.RequireClearedStageLevel.CombinationEquipmentAction); _initialState = _initialState.SetState(address, slotState.Serialize()); } }
public void CombinationSlotStateUpdate() { var address = new PrivateKey().PublicKey.ToAddress(); var state = new CombinationSlotState(address, 1); var result = new CombinationConsumable.ResultModel(); state.Update(result, 1, 10); Assert.AreEqual(result, state.Result); Assert.AreEqual(10, state.UnlockBlockIndex); Assert.AreEqual(1, state.StartBlockIndex); }
private void SetSlot(CombinationSlotState state) { var avatarState = States.Instance.CurrentAvatarState; if (avatarState is null) { return; } UpdateSlot(state); }
public void SetData(CombinationSlotState state, long blockIndex, int slotIndex) { lockText.text = string.Format( L10nManager.Localize("UI_UNLOCK_CONDITION_STAGE"), state.UnlockStage); _data = state; _slotIndex = slotIndex; var unlock = States.Instance.CurrentAvatarState?.worldInformation .IsStageCleared(state.UnlockStage) ?? false; lockText.gameObject.SetActive(!unlock); lockImage.gameObject.SetActive(!unlock); unlockText.gameObject.SetActive(false); progressText.gameObject.SetActive(false); progressBar.gameObject.SetActive(false); if (unlock) { var canUse = state.Validate(States.Instance.CurrentAvatarState, blockIndex); if (state.Result is null) { resultView.Clear(); } else { canUse = canUse && state.Result.itemUsable.RequiredBlockIndex <= blockIndex; if (canUse) { resultView.Clear(); } else { resultView.SetData(new Item(state.Result.itemUsable)); } progressText.text = state.Result.itemUsable.GetLocalizedName(); } unlockText.gameObject.SetActive(canUse); progressText.gameObject.SetActive(!canUse); progressBar.gameObject.SetActive(!canUse); SubscribeOnBlockIndex(blockIndex); Widget.Find <BottomMenu>()?.UpdateCombinationNotification(); } progressBar.maxValue = state.RequiredBlockIndex; progressBar.value = blockIndex - state.StartBlockIndex; sliderText.text = $"({progressBar.value} / {progressBar.maxValue})"; }
public void SerializeCombinationSlotStateWithOutResult() { var address = new PrivateKey().PublicKey.ToAddress(); var state = new CombinationSlotState(address, 1); var serialized = (Dictionary)state.Serialize(); Assert.IsTrue(serialized.ContainsKey((IKey)(Text)"address")); Assert.IsTrue(serialized.ContainsKey((IKey)(Text)"unlockBlockIndex")); Assert.IsTrue(serialized.ContainsKey((IKey)(Text)"unlockStage")); Assert.IsFalse(serialized.ContainsKey((IKey)(Text)"result")); var deserialize = new CombinationSlotState(serialized); Assert.AreEqual(state.UnlockStage, deserialize.UnlockStage); Assert.AreEqual(state.UnlockBlockIndex, deserialize.UnlockBlockIndex); Assert.AreEqual(state.address, deserialize.address); }
public static bool TryGetMail( this CombinationSlotState state, long blockIndex, long requiredBlockIndex, out CombinationMail combinationMail, out ItemEnhanceMail itemEnhanceMail) { combinationMail = null; itemEnhanceMail = null; if (!state.TryGetResultId(out var resultId)) { return(false); } switch (state.Result) { case ItemEnhancement.ResultModel r: itemEnhanceMail = new ItemEnhanceMail( r, blockIndex, resultId, requiredBlockIndex); return(true); case ItemEnhancement7.ResultModel r: itemEnhanceMail = new ItemEnhanceMail( r, blockIndex, resultId, requiredBlockIndex); return(true); case CombinationConsumable5.ResultModel r: combinationMail = new CombinationMail( r, blockIndex, resultId, requiredBlockIndex); return(true); default: return(false); } }
private void UpdateSlot(CombinationSlotState state) { for (var i = 0; i < slots.Length; i++) { var slot = slots[i]; var address = States.Instance.CurrentAvatarState.address.Derive( string.Format( CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, i ) ); if (address == state.address) { slot.SetData(state, _blockIndex, i); break; } } }
public CombinationSlotState Modify(CombinationSlotState state) { if (state is null) { return(null); } var address = state.address; if (!_combinationSlotModifierInfos.ContainsKey(address)) { return(state); } var modifierInfo = _combinationSlotModifierInfos[address]; return(modifierInfo is null ? state : PostModify(state, modifierInfo)); }
private void SetCombinationSlotStates(AvatarState avatarState) { if (avatarState is null) { LocalLayer.Instance.InitializeCombinationSlotsByCurrentAvatarState(null); return; } LocalLayer.Instance.InitializeCombinationSlotsByCurrentAvatarState(avatarState); for (var i = 0; i < avatarState.combinationSlotAddresses.Count; i++) { var slotAddress = avatarState.address.Derive( string.Format( CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, i ) ); var slotState = new CombinationSlotState( (Dictionary)Game.Game.instance.Agent.GetState(slotAddress)); SetCombinationSlotState(slotState); } }
public async Task Query() { const string query = @" { address unlockBlockIndex unlockStage startBlockIndex }"; Address address = default; CombinationSlotState combinationSlotState = new CombinationSlotState(address, 1); var queryResult = await ExecuteQueryAsync <CombinationSlotStateType>(query, source : combinationSlotState); var expected = new Dictionary <string, object>() { ["address"] = address.ToString(), ["unlockBlockIndex"] = 0, ["unlockStage"] = 1, ["startBlockIndex"] = 0, }; Assert.Equal(expected, queryResult.Data); }
public override IAccountStateDelta Execute(IActionContext context) { IActionContext ctx = context; var states = ctx.PreviousStates; var avatarAddress = ctx.Signer.Derive( string.Format( CultureInfo.InvariantCulture, DeriveFormat, index ) ); if (ctx.Rehearsal) { states = states.SetState(ctx.Signer, MarkChanged); for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) { var slotAddress = avatarAddress.Derive( string.Format( CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, i ) ); states = states.SetState(slotAddress, MarkChanged); } return(states .SetState(avatarAddress, MarkChanged) .SetState(Addresses.Ranking, MarkChanged) .MarkBalanceChanged(GoldCurrencyMock, GoldCurrencyState.Address, context.Signer)); } CheckObsolete(BlockChain.Policy.BlockPolicySource.V100080ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); if (!Regex.IsMatch(name, GameConfig.AvatarNickNamePattern)) { throw new InvalidNamePatternException( $"{addressesHex}Aborted as the input name {name} does not follow the allowed name pattern."); } var sw = new Stopwatch(); sw.Start(); var started = DateTimeOffset.UtcNow; Log.Verbose("{AddressesHex}CreateAvatar exec started", addressesHex); AgentState existingAgentState = states.GetAgentState(ctx.Signer); var agentState = existingAgentState ?? new AgentState(ctx.Signer); var avatarState = states.GetAvatarState(avatarAddress); if (!(avatarState is null)) { throw new InvalidAddressException( $"{addressesHex}Aborted as there is already an avatar at {avatarAddress}."); } if (!(0 <= index && index < GameConfig.SlotCount)) { throw new AvatarIndexOutOfRangeException( $"{addressesHex}Aborted as the index is out of range #{index}."); } if (agentState.avatarAddresses.ContainsKey(index)) { throw new AvatarIndexAlreadyUsedException( $"{addressesHex}Aborted as the signer already has an avatar at index #{index}."); } sw.Stop(); Log.Verbose("{AddressesHex}CreateAvatar Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); Log.Verbose("{AddressesHex}Execute CreateAvatar; player: {AvatarAddress}", addressesHex, avatarAddress); agentState.avatarAddresses.Add(index, avatarAddress); // Avoid NullReferenceException in test var materialItemSheet = ctx.PreviousStates.GetSheet <MaterialItemSheet>(); var rankingState = ctx.PreviousStates.GetRankingState(); var rankingMapAddress = rankingState.UpdateRankingMap(avatarAddress); avatarState = CreateAvatar0.CreateAvatarState(name, avatarAddress, ctx, materialItemSheet, rankingMapAddress); if (hair < 0) { hair = 0; } if (lens < 0) { lens = 0; } if (ear < 0) { ear = 0; } if (tail < 0) { tail = 0; } avatarState.Customize(hair, lens, ear, tail); foreach (var address in avatarState.combinationSlotAddresses) { var slotState = new CombinationSlotState(address, GameConfig.RequireClearedStageLevel.CombinationEquipmentAction); states = states.SetState(address, slotState.Serialize()); } avatarState.UpdateQuestRewards2(materialItemSheet); sw.Stop(); Log.Verbose("{AddressesHex}CreateAvatar CreateAvatarState: {Elapsed}", addressesHex, sw.Elapsed); var ended = DateTimeOffset.UtcNow; Log.Verbose("{AddressesHex}CreateAvatar Total Executed Time: {Elapsed}", addressesHex, ended - started); return(states .SetState(ctx.Signer, agentState.Serialize()) .SetState(Addresses.Ranking, rankingState.Serialize()) .SetState(avatarAddress, avatarState.Serialize())); }
public CombinationAndRapidCombinationTest(ITestOutputHelper outputHelper) { Log.Logger = new LoggerConfiguration() .MinimumLevel.Verbose() .WriteTo.TestOutput(outputHelper) .CreateLogger(); var sheets = TableSheetsImporter.ImportSheets(); _tableSheets = new TableSheets(sheets); var gold = new GoldCurrencyState(new Currency("NCG", 2, minter: null)); var gameConfigState = new GameConfigState(sheets[nameof(GameConfigSheet)]); _agentAddress = new PrivateKey().ToAddress(); _avatarAddress = _agentAddress.Derive("avatar"); _slot0Address = _avatarAddress.Derive( string.Format( CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, 0 ) ); var slot0State = new CombinationSlotState( _slot0Address, GameConfig.RequireClearedStageLevel.CombinationEquipmentAction); var agentState = new AgentState(_agentAddress); agentState.avatarAddresses[0] = _avatarAddress; var avatarState = new AvatarState( _avatarAddress, _agentAddress, 1, _tableSheets.GetAvatarSheets(), gameConfigState, default ) { worldInformation = new WorldInformation( 0, _tableSheets.WorldSheet, GameConfig.RequireClearedStageLevel.CombinationEquipmentAction), }; _inventoryAddress = _avatarAddress.Derive(LegacyInventoryKey); _worldInformationAddress = _avatarAddress.Derive(LegacyWorldInformationKey); _questListAddress = _avatarAddress.Derive(LegacyQuestListKey); _initialState = new Tests.Action.State() .SetState(GoldCurrencyState.Address, gold.Serialize()) .SetState(gameConfigState.address, gameConfigState.Serialize()) .SetState(_agentAddress, agentState.Serialize()) .SetState(_avatarAddress, avatarState.SerializeV2()) .SetState(_inventoryAddress, avatarState.inventory.Serialize()) .SetState(_worldInformationAddress, avatarState.worldInformation.Serialize()) .SetState(_questListAddress, avatarState.questList.Serialize()) .SetState(_slot0Address, slot0State.Serialize()); foreach (var(key, value) in sheets) { _initialState = _initialState .SetState(Addresses.TableSheet.Derive(key), value.Serialize()); } }
public void Case(int randomSeed, int[] optionNumbers) { var gameConfigState = _initialState.GetGameConfigState(); Assert.NotNull(gameConfigState); var recipeRow = _tableSheets.EquipmentItemRecipeSheet.OrderedList.First(e => e.SubRecipeIds.Any()); var subRecipeRow = _tableSheets.EquipmentItemSubRecipeSheetV2[recipeRow.SubRecipeIds.First()]; var combinationEquipmentAction = new CombinationEquipment { avatarAddress = _avatarAddress, slotIndex = 0, recipeId = recipeRow.Id, subRecipeId = subRecipeRow.Id, }; var inventoryValue = _initialState.GetState(_inventoryAddress); Assert.NotNull(inventoryValue); var inventoryState = new Inventory((List)inventoryValue); inventoryState.AddFungibleItem( ItemFactory.CreateMaterial(_tableSheets.MaterialItemSheet, recipeRow.MaterialId), recipeRow.MaterialCount); foreach (var materialInfo in subRecipeRow.Materials) { inventoryState.AddFungibleItem( ItemFactory.CreateMaterial(_tableSheets.MaterialItemSheet, materialInfo.Id), materialInfo.Count); } var worldInformation = new WorldInformation( 0, _tableSheets.WorldSheet, recipeRow.UnlockStage); var nextState = _initialState .SetState(_inventoryAddress, inventoryState.Serialize()) .SetState(_worldInformationAddress, worldInformation.Serialize()); var random = new TestRandom(randomSeed); nextState = combinationEquipmentAction.Execute(new ActionContext { PreviousStates = nextState, BlockIndex = 0, Random = random, Signer = _agentAddress, }); var slot0Value = nextState.GetState(_slot0Address); Assert.NotNull(slot0Value); var slot0State = new CombinationSlotState((Dictionary)slot0Value); Assert.NotNull(slot0State.Result.itemUsable); var equipment = (Equipment)slot0State.Result.itemUsable; var additionalStats = equipment.StatsMap .GetAdditionalStats(true) .ToArray(); var skills = equipment.Skills; Assert.Equal(optionNumbers.Length, equipment.optionCountFromCombination); var optionSheet = _tableSheets.EquipmentItemOptionSheet; var mainAdditionalStatMin = 0; var mainAdditionalStatMax = 0; var requiredBlockIndex = 0; foreach (var optionNumber in optionNumbers) { var optionInfo = subRecipeRow.Options[optionNumber - 1]; requiredBlockIndex += optionInfo.RequiredBlockIndex; var optionRow = optionSheet[optionInfo.Id]; if (optionRow.StatMin > 0 || optionRow.StatMax > 0) { if (optionRow.StatType == equipment.UniqueStatType) { mainAdditionalStatMin += optionRow.StatMin; mainAdditionalStatMax += optionRow.StatMax; continue; } var additionalStatValue = additionalStats .First(e => e.statType == optionRow.StatType) .additionalValue; Assert.True(additionalStatValue >= optionRow.StatMin); Assert.True(additionalStatValue <= optionRow.StatMax + 1); } else if (optionRow.SkillId != default) { var skill = skills.First(e => e.SkillRow.Id == optionRow.SkillId); Assert.True(skill.Chance >= optionRow.SkillChanceMin); Assert.True(skill.Chance <= optionRow.SkillChanceMax + 1); Assert.True(skill.Power >= optionRow.SkillDamageMin); Assert.True(skill.Power <= optionRow.SkillDamageMax + 1); } } var mainAdditionalStatValue = additionalStats .First(e => e.statType == equipment.UniqueStatType) .additionalValue; Assert.True(mainAdditionalStatValue >= mainAdditionalStatMin); Assert.True(mainAdditionalStatValue <= mainAdditionalStatMax + 1); Assert.Equal(requiredBlockIndex + 1, slot0State.RequiredBlockIndex); // FIXME // https://github.com/planetarium/lib9c/pull/517#discussion_r679218764 // The tests after this line should be finished. However, since then the logic is being developed by // different developers in different branches. I wrote a test beforehand, but it's failing. // I plan to move to another branch after this PR is merged and finish writing the tests. return; if (requiredBlockIndex == 0) { return; } var hourglassRow = _tableSheets.MaterialItemSheet .First(pair => pair.Value.ItemSubType == ItemSubType.Hourglass) .Value; inventoryValue = nextState.GetState(_inventoryAddress); Assert.NotNull(inventoryValue); inventoryState = new Inventory((List)inventoryValue); Assert.False(inventoryState.TryGetFungibleItems(hourglassRow.ItemId, out _)); var hourglassCount = requiredBlockIndex * gameConfigState.HourglassPerBlock; inventoryState.AddFungibleItem( ItemFactory.CreateMaterial(_tableSheets.MaterialItemSheet, hourglassRow.Id), hourglassCount); Assert.True(inventoryState.TryGetFungibleItems(hourglassRow.ItemId, out var hourglasses)); Assert.Equal(hourglassCount, hourglasses.Sum(e => e.count)); nextState = nextState.SetState(_inventoryAddress, inventoryState.Serialize()); var rapidCombinationAction = new RapidCombination { avatarAddress = _avatarAddress, slotIndex = 0, }; nextState = rapidCombinationAction.Execute(new ActionContext { PreviousStates = nextState, BlockIndex = 1, Random = random, Signer = _agentAddress, }); inventoryValue = nextState.GetState(_inventoryAddress); Assert.NotNull(inventoryValue); inventoryState = new Inventory((List)inventoryValue); Assert.False(inventoryState.TryGetFungibleItems(hourglassRow.ItemId, out _)); }
public static void OnNext(CombinationSlotState slotState) { CombinationSlotState.OnNext(slotState); }
public override IAccountStateDelta Execute(IActionContext context) { var data = TestbedHelper.LoadData <TestbedSell>("TestbedSell"); var addedItemInfos = data.Items .Select(item => new TestbedHelper.AddedItemInfo( context.Random.GenerateRandomGuid(), context.Random.GenerateRandomGuid())) .ToList(); var agentAddress = _privateKey.PublicKey.ToAddress(); var states = context.PreviousStates; var avatarAddress = agentAddress.Derive( string.Format( CultureInfo.InvariantCulture, CreateAvatar.DeriveFormat, _slotIndex ) ); var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); var orderReceiptAddress = OrderDigestListState.DeriveAddress(avatarAddress); if (context.Rehearsal) { states = states.SetState(agentAddress, MarkChanged); for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) { var slotAddress = avatarAddress.Derive( string.Format(CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, i)); states = states.SetState(slotAddress, MarkChanged); } states = states.SetState(avatarAddress, MarkChanged) .SetState(Addresses.Ranking, MarkChanged) .SetState(worldInformationAddress, MarkChanged) .SetState(questListAddress, MarkChanged) .SetState(inventoryAddress, MarkChanged); for (var i = 0; i < data.Items.Length; i++) { var itemAddress = Addresses.GetItemAddress(addedItemInfos[i].TradableId); var orderAddress = Order.DeriveAddress(addedItemInfos[i].OrderId); var shopAddress = ShardedShopStateV2.DeriveAddress( data.Items[i].ItemSubType, addedItemInfos[i].OrderId); states = states.SetState(avatarAddress, MarkChanged) .SetState(inventoryAddress, MarkChanged) .MarkBalanceChanged(GoldCurrencyMock, agentAddress, GoldCurrencyState.Address) .SetState(orderReceiptAddress, MarkChanged) .SetState(itemAddress, MarkChanged) .SetState(orderAddress, MarkChanged) .SetState(shopAddress, MarkChanged); } return(states); } // Create Agent and avatar var existingAgentState = states.GetAgentState(agentAddress); var agentState = existingAgentState ?? new AgentState(agentAddress); var avatarState = states.GetAvatarState(avatarAddress); if (!(avatarState is null)) { throw new InvalidAddressException( $"Aborted as there is already an avatar at {avatarAddress}."); } if (agentState.avatarAddresses.ContainsKey(_slotIndex)) { throw new AvatarIndexAlreadyUsedException( $"borted as the signer already has an avatar at index #{_slotIndex}."); } agentState.avatarAddresses.Add(_slotIndex, avatarAddress); var rankingState = context.PreviousStates.GetRankingState(); var rankingMapAddress = rankingState.UpdateRankingMap(avatarAddress); avatarState = TestbedHelper.CreateAvatarState(data.avatar.Name, agentAddress, avatarAddress, context.BlockIndex, context.PreviousStates.GetAvatarSheets(), context.PreviousStates.GetSheet <WorldSheet>(), context.PreviousStates.GetGameConfigState(), rankingMapAddress); // Add item var costumeItemSheet = context.PreviousStates.GetSheet <CostumeItemSheet>(); var equipmentItemSheet = context.PreviousStates.GetSheet <EquipmentItemSheet>(); var optionSheet = context.PreviousStates.GetSheet <EquipmentItemOptionSheet>(); var skillSheet = context.PreviousStates.GetSheet <SkillSheet>(); var materialItemSheet = context.PreviousStates.GetSheet <MaterialItemSheet>(); var consumableItemSheet = context.PreviousStates.GetSheet <ConsumableItemSheet>(); for (var i = 0; i < data.Items.Length; i++) { TestbedHelper.AddItem(costumeItemSheet, equipmentItemSheet, optionSheet, skillSheet, materialItemSheet, consumableItemSheet, context.Random, data.Items[i], addedItemInfos[i], avatarState); } avatarState.Customize(0, 0, 0, 0); foreach (var address in avatarState.combinationSlotAddresses) { var slotState = new CombinationSlotState(address, GameConfig.RequireClearedStageLevel.CombinationEquipmentAction); states = states.SetState(address, slotState.Serialize()); } avatarState.UpdateQuestRewards(materialItemSheet); states = states.SetState(agentAddress, agentState.Serialize()) .SetState(Addresses.Ranking, rankingState.Serialize()) .SetState(inventoryAddress, avatarState.inventory.Serialize()) .SetState(worldInformationAddress, avatarState.worldInformation.Serialize()) .SetState(questListAddress, avatarState.questList.Serialize()) .SetState(avatarAddress, avatarState.SerializeV2()); // for sell for (var i = 0; i < data.Items.Length; i++) { var itemAddress = Addresses.GetItemAddress(addedItemInfos[i].TradableId); var orderAddress = Order.DeriveAddress(addedItemInfos[i].OrderId); var shopAddress = ShardedShopStateV2.DeriveAddress( data.Items[i].ItemSubType, addedItemInfos[i].OrderId); var balance = context.PreviousStates.GetBalance(agentAddress, states.GetGoldCurrency()); var price = new FungibleAssetValue(balance.Currency, data.Items[i].Price, 0); var order = OrderFactory.Create(agentAddress, avatarAddress, addedItemInfos[i].OrderId, price, addedItemInfos[i].TradableId, context.BlockIndex, data.Items[i].ItemSubType, data.Items[i].Count); Orders.Add(order); order.Validate(avatarState, data.Items[i].Count); var tradableItem = order.Sell(avatarState); var shardedShopState = states.TryGetState(shopAddress, out Dictionary serializedState) ? new ShardedShopStateV2(serializedState) : new ShardedShopStateV2(shopAddress); var costumeStatSheet = states.GetSheet <CostumeStatSheet>(); var orderDigest = order.Digest(avatarState, costumeStatSheet); shardedShopState.Add(orderDigest, context.BlockIndex); var orderReceiptList = states.TryGetState(orderReceiptAddress, out Dictionary receiptDict) ? new OrderDigestListState(receiptDict) : new OrderDigestListState(orderReceiptAddress); orderReceiptList.Add(orderDigest); states = states.SetState(orderReceiptAddress, orderReceiptList.Serialize()) .SetState(inventoryAddress, avatarState.inventory.Serialize()) .SetState(avatarAddress, avatarState.SerializeV2()) .SetState(itemAddress, tradableItem.Serialize()) .SetState(orderAddress, order.Serialize()) .SetState(shopAddress, shardedShopState.Serialize()); } result.SellerAgentAddress = agentAddress; result.SellerAvatarAddress = avatarAddress; result.ItemInfos = new List <ItemInfos>(); for (var i = 0; i < data.Items.Length; i++) { result.ItemInfos.Add(new ItemInfos( addedItemInfos[i].OrderId, addedItemInfos[i].TradableId, data.Items[i].ItemSubType, data.Items[i].Price, data.Items[i].Count)); } return(states); }
public void Pop(CombinationSlotState state, int slotIndex) { _slotIndex = slotIndex; CombinationConsumable.ResultModel result; CombinationConsumable.ResultModel chainResult; try { result = (CombinationConsumable.ResultModel)state.Result; var chainState = new CombinationSlotState((Dictionary)Game.Game.instance.Agent.GetState(state.address)); chainResult = (CombinationConsumable.ResultModel)chainState.Result; } catch (InvalidCastException) { return; } var subRecipeEnabled = result.subRecipeId.HasValue; materialPanel.gameObject.SetActive(false); optionView.gameObject.SetActive(false); switch (result.itemType) { case ItemType.Equipment: { var recipeRow = Game.Game.instance.TableSheets.EquipmentItemRecipeSheet.Values.First(r => r.Id == result.recipeId); recipeCellView.Set(recipeRow); if (subRecipeEnabled) { optionView.Show( result.itemUsable.GetLocalizedName(), (int)result.subRecipeId, new EquipmentItemSubRecipeSheet.MaterialInfo( recipeRow.MaterialId, recipeRow.MaterialCount), false ); } else { materialPanel.SetData(recipeRow, null, false); materialPanel.gameObject.SetActive(true); } break; } case ItemType.Consumable: { var recipeRow = Game.Game.instance.TableSheets.ConsumableItemRecipeSheet.Values.First(r => r.Id == result.recipeId); recipeCellView.Set(recipeRow); materialPanel.SetData(recipeRow, false, true); materialPanel.gameObject.SetActive(true); break; } } submitButton.HideAP(); submitButton.HideNCG(); var diff = result.itemUsable.RequiredBlockIndex - Game.Game.instance.Agent.BlockIndex; if (diff < 0) { submitButton.SetSubmitText( L10nManager.Localize("UI_COMBINATION_WAITING"), L10nManager.Localize("UI_RAPID_COMBINATION") ); submitButton.SetSubmittable(result.id == chainResult?.id); submitButton.HideHourglass(); } else { _cost = Action.RapidCombination.CalculateHourglassCount( States.Instance.GameConfigState, diff); _row = Game.Game.instance.TableSheets.MaterialItemSheet.Values .First(r => r.ItemSubType == ItemSubType.Hourglass); var isEnough = States.Instance.CurrentAvatarState.inventory.HasItem(_row.ItemId, _cost); var count = States.Instance.CurrentAvatarState.inventory .TryGetMaterial(_row.ItemId, out var glass) ? glass.count : 0; if (result.id == chainResult?.id) { submitButton.SetSubmitText( L10nManager.Localize("UI_RAPID_COMBINATION")); submitButton.SetSubmittable(isEnough); } else { submitButton.SetSubmitText( L10nManager.Localize("UI_COMBINATION_WAITING")); submitButton.SetSubmittable(false); } submitButton.ShowHourglass(_cost, count); } base.Show(); }
public override CombinationSlotState Modify(CombinationSlotState state) { state.Update(_blockIndex); return(state); }
public void Case(int randomSeed, int[] optionNumbers) { var gameConfigState = _initialState.GetGameConfigState(); Assert.NotNull(gameConfigState); var subRecipeRow = _tableSheets.EquipmentItemSubRecipeSheetV2.OrderedList.First(e => e.Options.Count == 4 && e.RequiredBlockIndex > GameConfig.RequiredAppraiseBlock && e.RequiredGold == 0); var recipeRow = _tableSheets.EquipmentItemRecipeSheet.OrderedList.First(e => e.SubRecipeIds.Contains(subRecipeRow.Id)); var combinationEquipmentAction = new CombinationEquipment { avatarAddress = _avatarAddress, slotIndex = 0, recipeId = recipeRow.Id, subRecipeId = subRecipeRow.Id, }; var inventoryValue = _initialState.GetState(_inventoryAddress); Assert.NotNull(inventoryValue); var inventoryState = new Inventory((List)inventoryValue); inventoryState.AddFungibleItem( ItemFactory.CreateMaterial(_tableSheets.MaterialItemSheet, recipeRow.MaterialId), recipeRow.MaterialCount); foreach (var materialInfo in subRecipeRow.Materials) { inventoryState.AddFungibleItem( ItemFactory.CreateMaterial(_tableSheets.MaterialItemSheet, materialInfo.Id), materialInfo.Count); } var worldInformation = new WorldInformation( 0, _tableSheets.WorldSheet, recipeRow.UnlockStage); var nextState = _initialState .SetState(_inventoryAddress, inventoryState.Serialize()) .SetState(_worldInformationAddress, worldInformation.Serialize()); var random = new TestRandom(randomSeed); nextState = combinationEquipmentAction.Execute(new ActionContext { PreviousStates = nextState, BlockIndex = 0, Random = random, Signer = _agentAddress, }); var slot0Value = nextState.GetState(_slot0Address); Assert.NotNull(slot0Value); var slot0State = new CombinationSlotState((Dictionary)slot0Value); Assert.NotNull(slot0State.Result.itemUsable); var equipment = (Equipment)slot0State.Result.itemUsable; var additionalStats = equipment.StatsMap .GetAdditionalStats(true) .ToArray(); var skills = equipment.Skills; Assert.Equal(optionNumbers.Length, equipment.optionCountFromCombination); var optionSheet = _tableSheets.EquipmentItemOptionSheet; var mainAdditionalStatMin = 0; var mainAdditionalStatMax = 0; var requiredBlockIndex = recipeRow.RequiredBlockIndex + subRecipeRow.RequiredBlockIndex; var orderedOptions = subRecipeRow.Options .OrderByDescending(e => e.Ratio) .ThenBy(e => e.RequiredBlockIndex) .ThenBy(e => e.Id) .ToArray(); foreach (var optionNumber in optionNumbers) { var optionInfo = orderedOptions[optionNumber - 1]; requiredBlockIndex += optionInfo.RequiredBlockIndex; var optionRow = optionSheet[optionInfo.Id]; if (optionRow.StatMin > 0 || optionRow.StatMax > 0) { if (optionRow.StatType == equipment.UniqueStatType) { mainAdditionalStatMin += optionRow.StatMin; mainAdditionalStatMax += optionRow.StatMax; continue; } var additionalStatValue = additionalStats .First(e => e.statType == optionRow.StatType) .additionalValue; Assert.True(additionalStatValue >= optionRow.StatMin); Assert.True(additionalStatValue <= optionRow.StatMax + 1); } else if (optionRow.SkillId != default) { var skill = skills.First(e => e.SkillRow.Id == optionRow.SkillId); Assert.True(skill.Chance >= optionRow.SkillChanceMin); Assert.True(skill.Chance <= optionRow.SkillChanceMax + 1); Assert.True(skill.Power >= optionRow.SkillDamageMin); Assert.True(skill.Power <= optionRow.SkillDamageMax + 1); } } var mainAdditionalStatValue = additionalStats .First(e => e.statType == equipment.UniqueStatType) .additionalValue; Assert.True(mainAdditionalStatValue >= mainAdditionalStatMin); Assert.True(mainAdditionalStatValue <= mainAdditionalStatMax + 1); Assert.Equal(requiredBlockIndex, slot0State.RequiredBlockIndex); if (requiredBlockIndex == 0) { return; } var hourglassRow = _tableSheets.MaterialItemSheet .First(pair => pair.Value.ItemSubType == ItemSubType.Hourglass) .Value; inventoryValue = nextState.GetState(_inventoryAddress); Assert.NotNull(inventoryValue); inventoryState = new Inventory((List)inventoryValue); Assert.False(inventoryState.TryGetFungibleItems(hourglassRow.ItemId, out _)); var diff = slot0State.RequiredBlockIndex - GameConfig.RequiredAppraiseBlock; var hourglassCount = RapidCombination0.CalculateHourglassCount(gameConfigState, diff); inventoryState.AddFungibleItem( ItemFactory.CreateMaterial(_tableSheets.MaterialItemSheet, hourglassRow.Id), hourglassCount); Assert.True(inventoryState.TryGetFungibleItems(hourglassRow.ItemId, out var hourglasses)); Assert.Equal(hourglassCount, hourglasses.Sum(e => e.count)); nextState = nextState.SetState(_inventoryAddress, inventoryState.Serialize()); var rapidCombinationAction = new RapidCombination { avatarAddress = _avatarAddress, slotIndex = 0, }; nextState = rapidCombinationAction.Execute(new ActionContext { PreviousStates = nextState, BlockIndex = GameConfig.RequiredAppraiseBlock, Random = random, Signer = _agentAddress, }); inventoryValue = nextState.GetState(_inventoryAddress); Assert.NotNull(inventoryValue); inventoryState = new Inventory((List)inventoryValue); Assert.False(inventoryState.TryGetFungibleItems(hourglassRow.ItemId, out _)); }
public override IAccountStateDelta Execute(IActionContext context) { IActionContext ctx = context; var states = ctx.PreviousStates; if (ctx.Rehearsal) { states = states.SetState(ctx.Signer, MarkChanged); for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) { var slotAddress = avatarAddress.Derive( string.Format( CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, i ) ); states = states.SetState(slotAddress, MarkChanged); } return(states .SetState(avatarAddress, MarkChanged) .MarkBalanceChanged(GoldCurrencyMock, GoldCurrencyState.Address, context.Signer)); } if (!Regex.IsMatch(name, GameConfig.AvatarNickNamePattern)) { return(LogError( context, "Aborted as the input name {@Name} does not follow the allowed name pattern.", name )); } var sw = new Stopwatch(); sw.Start(); var started = DateTimeOffset.UtcNow; Log.Debug("CreateAvatar exec started."); AgentState existingAgentState = states.GetAgentState(ctx.Signer); var agentState = existingAgentState ?? new AgentState(ctx.Signer); var avatarState = states.GetAvatarState(avatarAddress); if (!(avatarState is null)) { return(LogError(context, "Aborted as there is already an avatar at {Address}.", avatarAddress)); } if (agentState.avatarAddresses.ContainsKey(index)) { return(LogError(context, "Aborted as the signer already has an avatar at index #{Index}.", index)); } sw.Stop(); Log.Debug("CreateAvatar Get AgentAvatarStates: {Elapsed}", sw.Elapsed); sw.Restart(); if (existingAgentState is null) { // 첫 아바타 생성이면 계정당 기본 소지금 부여. states = states.TransferAsset( GoldCurrencyState.Address, ctx.Signer, states.GetGoldCurrency(), InitialGoldBalance ); } Log.Debug("Execute CreateAvatar; player: {AvatarAddress}", avatarAddress); agentState.avatarAddresses.Add(index, avatarAddress); // Avoid NullReferenceException in test avatarState = CreateAvatarState(name, avatarAddress, ctx); if (hair < 0) { hair = 0; } if (lens < 0) { lens = 0; } if (ear < 0) { ear = 0; } if (tail < 0) { tail = 0; } avatarState.Customize(hair, lens, ear, tail); foreach (var address in avatarState.combinationSlotAddresses) { var slotState = new CombinationSlotState(address, GameConfig.RequireClearedStageLevel.CombinationEquipmentAction); states = states.SetState(address, slotState.Serialize()); } avatarState.UpdateQuestRewards(ctx); sw.Stop(); Log.Debug("CreateAvatar CreateAvatarState: {Elapsed}", sw.Elapsed); var ended = DateTimeOffset.UtcNow; Log.Debug("CreateAvatar Total Executed Time: {Elapsed}", ended - started); return(states .SetState(ctx.Signer, agentState.Serialize()) .SetState(avatarAddress, avatarState.Serialize())); }