Пример #1
0
        public void SerializeBattleLog()
        {
            var agentState  = new AgentState(new Address());
            var avatarState = new AvatarState(
                new Address(),
                agentState.address,
                0,
                _tableSheets.GetAvatarSheets(),
                new GameConfigState(),
                default
                );
            var arenaInfo = new ArenaInfo(avatarState, _tableSheets.CharacterSheet, false);
            var simulator = new RankingSimulator(
                new Cheat.DebugRandom(),
                avatarState,
                avatarState,
                new List <Guid>(),
                _tableSheets.GetRankingSimulatorSheets(),
                999999,
                arenaInfo,
                arenaInfo
                );

            simulator.SimulateV2();

            void ToBytes()
            {
                var formatter = new BinaryFormatter();

                using (var stream = new MemoryStream())
                {
                    formatter.Serialize(stream, simulator.Log);
                    stream.ToArray();
                }
            }

            Assert.DoesNotThrow(ToBytes);
        }
Пример #2
0
        public void Execute(bool isNew, bool avatarBackward, bool enemyBackward)
        {
            var previousWeeklyState  = _initialState.GetWeeklyArenaState(0);
            var previousAvatar1State = _initialState.GetAvatarState(_avatar1Address);

            previousAvatar1State.level = 10;
            var prevScore = previousWeeklyState[_avatar1Address].Score;

            if (isNew)
            {
                previousWeeklyState.Remove(_avatar1Address);
            }

            var previousState = _initialState.SetState(
                _avatar1Address,
                previousAvatar1State.Serialize());

            var itemIds = _tableSheets.WeeklyArenaRewardSheet.Values
                          .Select(r => r.Reward.ItemId)
                          .ToList();

            Assert.All(itemIds, id => Assert.False(previousAvatar1State.inventory.HasItem(id)));

            var row     = _tableSheets.CostumeStatSheet.Values.First(r => r.StatType == StatType.ATK);
            var costume = (Costume)ItemFactory.CreateItem(
                _tableSheets.ItemSheet[row.CostumeId], new TestRandom());

            costume.equipped = true;
            previousAvatar1State.inventory.AddItem(costume);

            var row2         = _tableSheets.CostumeStatSheet.Values.First(r => r.StatType == StatType.DEF);
            var enemyCostume = (Costume)ItemFactory.CreateItem(
                _tableSheets.ItemSheet[row2.CostumeId], new TestRandom());

            enemyCostume.equipped = true;
            var enemyAvatarState = _initialState.GetAvatarState(_avatar2Address);

            enemyAvatarState.inventory.AddItem(enemyCostume);

            if (avatarBackward)
            {
                previousState =
                    previousState.SetState(_avatar1Address, previousAvatar1State.Serialize());
            }
            else
            {
                previousState = previousState
                                .SetState(
                    _avatar1Address.Derive(LegacyInventoryKey),
                    previousAvatar1State.inventory.Serialize())
                                .SetState(
                    _avatar1Address.Derive(LegacyWorldInformationKey),
                    previousAvatar1State.worldInformation.Serialize())
                                .SetState(
                    _avatar1Address.Derive(LegacyQuestListKey),
                    previousAvatar1State.questList.Serialize())
                                .SetState(_avatar1Address, previousAvatar1State.SerializeV2());
            }

            if (enemyBackward)
            {
                previousState =
                    previousState.SetState(_avatar2Address, enemyAvatarState.Serialize());
            }
            else
            {
                previousState = previousState
                                .SetState(
                    _avatar2Address.Derive(LegacyInventoryKey),
                    enemyAvatarState.inventory.Serialize())
                                .SetState(
                    _avatar2Address.Derive(LegacyWorldInformationKey),
                    enemyAvatarState.worldInformation.Serialize())
                                .SetState(
                    _avatar2Address.Derive(LegacyQuestListKey),
                    enemyAvatarState.questList.Serialize())
                                .SetState(_avatar2Address, enemyAvatarState.SerializeV2());
            }

            var action = new RankingBattle8
            {
                avatarAddress      = _avatar1Address,
                enemyAddress       = _avatar2Address,
                weeklyArenaAddress = _weeklyArenaAddress,
                costumeIds         = new List <Guid> {
                    costume.ItemId
                },
                equipmentIds  = new List <Guid>(),
                consumableIds = new List <Guid>(),
            };

            Assert.Null(action.Result);

            var nextState = action.Execute(new ActionContext()
            {
                PreviousStates = previousState,
                Signer         = _agent1Address,
                Random         = new TestRandom(),
                Rehearsal      = false,
            });

            var nextAvatar1State = nextState.GetAvatarStateV2(_avatar1Address);
            var nextWeeklyState  = nextState.GetWeeklyArenaState(0);

            Assert.Contains(nextAvatar1State.inventory.Materials, i => itemIds.Contains(i.Id));
            Assert.NotNull(action.Result);
            Assert.NotNull(action.ArenaInfo);
            Assert.NotNull(action.EnemyArenaInfo);
            Assert.NotNull(action.EnemyAvatarState);
            Assert.Contains(typeof(GetReward), action.Result.Select(e => e.GetType()));
            Assert.Equal(BattleLog.Result.Win, action.Result.result);
            Assert.True(nextWeeklyState[_avatar1Address].Score > prevScore);

            // Check simulation result equal.
            var simulator = new RankingSimulator(
                new TestRandom(),
                previousAvatar1State,
                action.EnemyAvatarState,
                action.consumableIds,
                _tableSheets.GetRankingSimulatorSheets(),
                RankingBattle8.StageId,
                action.ArenaInfo,
                action.EnemyArenaInfo,
                _tableSheets.CostumeStatSheet);

            simulator.Simulate();

            BattleLog log    = simulator.Log;
            BattleLog result = action.Result;

            Assert.Equal(result.score, log.score);
            Assert.Equal(result.Count, log.Count);
            Assert.Equal(result.result, log.result);
        }
Пример #3
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IActionContext ctx    = context;
            var            states = ctx.PreviousStates;

            if (ctx.Rehearsal)
            {
                return(states.SetState(ctx.Signer, MarkChanged)
                       .SetState(AvatarAddress, MarkChanged)
                       .SetState(WeeklyArenaAddress, MarkChanged)
                       .SetState(ctx.Signer, MarkChanged)
                       .MarkBalanceChanged(GoldCurrencyMock, ctx.Signer, WeeklyArenaAddress));
            }

            CheckObsolete(BlockChain.Policy.BlockPolicySource.V100080ObsoleteIndex, context);

            var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress, EnemyAddress);

            Log.Warning("ranking_battle is deprecated. Please use ranking_battle2");
            if (AvatarAddress.Equals(EnemyAddress))
            {
                throw new InvalidAddressException($"{addressesHex}Aborted as the signer tried to battle for themselves.");
            }

            if (!states.TryGetAgentAvatarStates(
                    ctx.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 costumes = new HashSet <int>(costumeIds);

            avatarState.ValidateEquipments(equipmentIds, context.BlockIndex);
            avatarState.ValidateConsumable(consumableIds, context.BlockIndex);
            avatarState.ValidateCostume(costumes);

            if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world) ||
                world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard)
            {
                throw new NotEnoughClearedStageLevelException(
                          addressesHex,
                          GameConfig.RequireClearedStageLevel.ActionsInRankingBoard,
                          world.StageClearedId);
            }

            avatarState.EquipCostumes(costumes);
            avatarState.EquipEquipments(equipmentIds);

            var enemyAvatarState = states.GetAvatarState(EnemyAddress);

            if (enemyAvatarState is null)
            {
                throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the opponent ({EnemyAddress}) was failed to load.");
            }

            var weeklyArenaState = states.GetWeeklyArenaState(WeeklyArenaAddress);

            if (weeklyArenaState.Ended)
            {
                throw new WeeklyArenaStateAlreadyEndedException(
                          addressesHex + WeeklyArenaStateAlreadyEndedException.BaseMessage);
            }

            if (!weeklyArenaState.ContainsKey(AvatarAddress))
            {
                throw new WeeklyArenaStateNotContainsAvatarAddressException(addressesHex, AvatarAddress);
            }

            var arenaInfo = weeklyArenaState[AvatarAddress];

            if (arenaInfo.DailyChallengeCount <= 0)
            {
                throw new NotEnoughWeeklyArenaChallengeCountException(
                          addressesHex + NotEnoughWeeklyArenaChallengeCountException.BaseMessage);
            }

            if (!arenaInfo.Active)
            {
                FungibleAssetValue agentBalance = default;
                try
                {
                    agentBalance = states.GetBalance(ctx.Signer, states.GetGoldCurrency());
                }
                catch (InvalidOperationException)
                {
                    throw new NotEnoughFungibleAssetValueException(addressesHex, EntranceFee, agentBalance);
                }

                if (agentBalance >= new FungibleAssetValue(agentBalance.Currency, EntranceFee, 0))
                {
                    states = states.TransferAsset(
                        ctx.Signer,
                        WeeklyArenaAddress,
                        new FungibleAssetValue(
                            states.GetGoldCurrency(),
                            EntranceFee,
                            0
                            )
                        );
                    arenaInfo.Activate();
                }
                else
                {
                    throw new NotEnoughFungibleAssetValueException(addressesHex, EntranceFee, agentBalance);
                }
            }

            if (!weeklyArenaState.ContainsKey(EnemyAddress))
            {
                throw new WeeklyArenaStateNotContainsAvatarAddressException(addressesHex, EnemyAddress);
            }

            Log.Verbose("{WeeklyArenaStateAddress}", weeklyArenaState.address.ToHex());

            var simulator = new RankingSimulator(
                ctx.Random,
                avatarState,
                enemyAvatarState,
                consumableIds,
                states.GetRankingSimulatorSheets(),
                StageId,
                arenaInfo,
                weeklyArenaState[EnemyAddress]);

            simulator.Simulate2();

            Result = simulator.Log;

            foreach (var itemBase in simulator.Reward.OrderBy(i => i.Id))
            {
                avatarState.inventory.AddItem2(itemBase);
            }

            return(states
                   .SetState(ctx.Signer, agentState.Serialize())
                   .SetState(WeeklyArenaAddress, weeklyArenaState.Serialize())
                   .SetState(AvatarAddress, avatarState.Serialize()));
        }
Пример #4
0
        public void Execute_Backward_Compatible(bool isNew, bool avatarBackward, bool enemyBackward)
        {
            var previousWeeklyState  = _initialState.GetWeeklyArenaState(ArenaIndex);
            var previousAvatar1State = _initialState.GetAvatarState(_avatar1Address);

            previousAvatar1State.level = 10;
            var prevScore = previousWeeklyState[_avatar1Address].Score;

            if (isNew)
            {
                previousWeeklyState.Remove(_avatar1Address);
            }

            var previousState = _initialState.SetState(
                _avatar1Address,
                previousAvatar1State.Serialize());

            var itemIds = _tableSheets.WeeklyArenaRewardSheet.Values
                          .Select(r => r.Reward.ItemId)
                          .ToList();

            Assert.All(itemIds, id => Assert.False(previousAvatar1State.inventory.HasItem(id)));

            var row     = _tableSheets.CostumeStatSheet.Values.First(r => r.StatType == StatType.ATK);
            var costume = (Costume)ItemFactory.CreateItem(
                _tableSheets.ItemSheet[row.CostumeId], new TestRandom());

            costume.equipped = true;
            previousAvatar1State.inventory.AddItem(costume);

            var row2         = _tableSheets.CostumeStatSheet.Values.First(r => r.StatType == StatType.DEF);
            var enemyCostume = (Costume)ItemFactory.CreateItem(
                _tableSheets.ItemSheet[row2.CostumeId], new TestRandom());

            enemyCostume.equipped = true;
            var enemyAvatarState = _initialState.GetAvatarState(_avatar2Address);

            enemyAvatarState.inventory.AddItem(enemyCostume);

            Address worldInformationAddress = _avatar1Address.Derive(LegacyWorldInformationKey);

            if (avatarBackward)
            {
                previousState =
                    previousState.SetState(_avatar1Address, previousAvatar1State.Serialize());
            }
            else
            {
                previousState = previousState
                                .SetState(
                    _avatar1Address.Derive(LegacyInventoryKey),
                    previousAvatar1State.inventory.Serialize())
                                .SetState(
                    worldInformationAddress,
                    previousAvatar1State.worldInformation.Serialize())
                                .SetState(
                    _avatar1Address.Derive(LegacyQuestListKey),
                    previousAvatar1State.questList.Serialize())
                                .SetState(_avatar1Address, previousAvatar1State.SerializeV2());
            }

            if (enemyBackward)
            {
                previousState =
                    previousState.SetState(_avatar2Address, enemyAvatarState.Serialize());
            }
            else
            {
                previousState = previousState
                                .SetState(
                    _avatar2Address.Derive(LegacyInventoryKey),
                    enemyAvatarState.inventory.Serialize())
                                .SetState(
                    _avatar2Address.Derive(LegacyWorldInformationKey),
                    enemyAvatarState.worldInformation.Serialize())
                                .SetState(
                    _avatar2Address.Derive(LegacyQuestListKey),
                    enemyAvatarState.questList.Serialize())
                                .SetState(_avatar2Address, enemyAvatarState.SerializeV2());
            }

            var action = new RankingBattle
            {
                avatarAddress      = _avatar1Address,
                enemyAddress       = _avatar2Address,
                weeklyArenaAddress = _weeklyArenaAddress,
                costumeIds         = new List <Guid> {
                    costume.ItemId
                },
                equipmentIds = new List <Guid>(),
            };

            var nextState = action.Execute(new ActionContext
            {
                PreviousStates = previousState,
                Signer         = _agent1Address,
                Random         = new TestRandom(),
                Rehearsal      = false,
                BlockIndex     = RankingBattle.UpdateTargetBlockIndex - 1,
            });

            var nextAvatar1State = nextState.GetAvatarStateV2(_avatar1Address);
            var nextWeeklyState  = nextState.GetWeeklyArenaState(ArenaIndex);
            var nextArenaInfo    = nextWeeklyState[_avatar1Address];

            Assert.Contains(nextAvatar1State.inventory.Materials, i => itemIds.Contains(i.Id));
            Assert.NotNull(action.ArenaInfo);
            Assert.NotNull(action.EnemyArenaInfo);
            Assert.True(nextArenaInfo.Score > prevScore);

            // Check simulation result equal.
            var player = new Player(
                previousAvatar1State,
                _tableSheets.CharacterSheet,
                _tableSheets.CharacterLevelSheet,
                _tableSheets.EquipmentItemSetEffectSheet);
            var simulator = new RankingSimulator(
                new TestRandom(),
                player,
                action.EnemyPlayerDigest,
                new List <Guid>(),
                _tableSheets.GetRankingSimulatorSheets(),
                RankingBattle.StageId,
                action.ArenaInfo,
                action.EnemyArenaInfo,
                _tableSheets.CostumeStatSheet);

            simulator.Simulate();

            Assert.Equal(nextArenaInfo.Score, simulator.Log.score);
            Assert.Equal(previousAvatar1State.SerializeV2(), nextAvatar1State.SerializeV2());
            Assert.Equal(previousAvatar1State.worldInformation.Serialize(), nextAvatar1State.worldInformation.Serialize());
        }
Пример #5
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IActionContext ctx    = context;
            var            states = ctx.PreviousStates;

            if (ctx.Rehearsal)
            {
                return(states.SetState(ctx.Signer, MarkChanged)
                       .SetState(AvatarAddress, MarkChanged)
                       .SetState(WeeklyArenaAddress, MarkChanged)
                       .SetState(ctx.Signer, MarkChanged)
                       .MarkBalanceChanged(GoldCurrencyMock, ctx.Signer, WeeklyArenaAddress));
            }

            if (AvatarAddress.Equals(EnemyAddress))
            {
                throw new InvalidAddressException("Aborted as the signer tried to battle for themselves.");
            }

            if (!states.TryGetAvatarState(ctx.Signer, AvatarAddress, out var avatarState))
            {
                throw new FailedLoadStateException("Aborted as the avatar state of the signer was failed to load.");
            }

            avatarState.ValidateEquipments(equipmentIds, context.BlockIndex);
            avatarState.ValidateConsumable(consumableIds, context.BlockIndex);

            if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world) ||
                world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard)
            {
                throw new NotEnoughClearedStageLevelException(
                          GameConfig.RequireClearedStageLevel.ActionsInRankingBoard,
                          world.StageClearedId);
            }

            avatarState.EquipCostumes(new HashSet <int>(costumeIds));
            avatarState.EquipEquipments(equipmentIds);
            avatarState.ValidateCostume(new HashSet <int>(costumeIds));

            var enemyAvatarState = states.GetAvatarState(EnemyAddress);

            if (enemyAvatarState is null)
            {
                throw new FailedLoadStateException($"Aborted as the avatar state of the opponent ({EnemyAddress}) was failed to load.");
            }

            var weeklyArenaState = states.GetWeeklyArenaState(WeeklyArenaAddress);

            if (weeklyArenaState.Ended)
            {
                throw new WeeklyArenaStateAlreadyEndedException();
            }

            if (!weeklyArenaState.ContainsKey(AvatarAddress))
            {
                throw new WeeklyArenaStateNotContainsAvatarAddressException(AvatarAddress);
            }

            var arenaInfo = weeklyArenaState[AvatarAddress];

            if (arenaInfo.DailyChallengeCount <= 0)
            {
                throw new NotEnoughWeeklyArenaChallengeCountException();
            }

            if (!arenaInfo.Active)
            {
                arenaInfo.Activate();
            }

            if (!weeklyArenaState.ContainsKey(EnemyAddress))
            {
                throw new WeeklyArenaStateNotContainsAvatarAddressException(EnemyAddress);
            }

            Log.Debug(weeklyArenaState.address.ToHex());

            var costumeStatSheet = states.GetSheet <CostumeStatSheet>();
            var simulator        = new RankingSimulator(
                ctx.Random,
                avatarState,
                enemyAvatarState,
                consumableIds,
                states.GetRankingSimulatorSheets(),
                StageId,
                arenaInfo,
                weeklyArenaState[EnemyAddress],
                costumeStatSheet);

            simulator.Simulate();

            Result = simulator.Log;

            foreach (var itemBase in simulator.Reward.OrderBy(i => i.Id))
            {
                avatarState.inventory.AddItem(itemBase);
            }

            return(states
                   .SetState(WeeklyArenaAddress, weeklyArenaState.Serialize())
                   .SetState(AvatarAddress, avatarState.Serialize()));
        }
Пример #6
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IActionContext ctx                     = context;
            var            states                  = ctx.PreviousStates;
            var            inventoryAddress        = avatarAddress.Derive(LegacyInventoryKey);
            var            worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey);
            var            questListAddress        = avatarAddress.Derive(LegacyQuestListKey);

            if (ctx.Rehearsal)
            {
                return(states
                       .SetState(avatarAddress, MarkChanged)
                       .SetState(weeklyArenaAddress, MarkChanged)
                       .SetState(inventoryAddress, MarkChanged)
                       .SetState(worldInformationAddress, MarkChanged)
                       .SetState(questListAddress, MarkChanged));
            }

            CheckObsolete(BlockChain.Policy.BlockPolicySource.V100089ObsoleteIndex, context);

            // Avoid InvalidBlockStateRootHashException
            if (ctx.BlockIndex == 680341 && Id.Equals(new Guid("df37dbd8-5703-4dff-918b-ad22ee4c34c6")))
            {
                return(states);
            }

            var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress, enemyAddress);

            var sw = new Stopwatch();

            sw.Start();
            var started = DateTimeOffset.UtcNow;

            Log.Verbose(
                "{AddressesHex}RankingBattle exec started. costume: ({CostumeIds}), equipment: ({EquipmentIds})",
                addressesHex,
                string.Join(",", costumeIds),
                string.Join(",", equipmentIds)
                );

            if (avatarAddress.Equals(enemyAddress))
            {
                throw new InvalidAddressException($"{addressesHex}Aborted as the signer tried to battle for themselves.");
            }

            if (!states.TryGetAvatarStateV2(ctx.Signer, avatarAddress, out var avatarState, out _))
            {
                throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load.");
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            var items = equipmentIds.Concat(costumeIds);

            avatarState.ValidateEquipmentsV2(equipmentIds, context.BlockIndex);
            avatarState.ValidateConsumable(consumableIds, context.BlockIndex);
            avatarState.ValidateCostume(costumeIds);

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Validate Equipments: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            avatarState.EquipItems(items);

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Equip Equipments: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world) ||
                world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard)
            {
                throw new NotEnoughClearedStageLevelException(
                          addressesHex,
                          GameConfig.RequireClearedStageLevel.ActionsInRankingBoard,
                          world.StageClearedId);
            }

            AvatarState enemyAvatarState;

            try
            {
                enemyAvatarState = states.GetAvatarStateV2(enemyAddress);
            }
            // BackWard compatible.
            catch (FailedLoadStateException)
            {
                enemyAvatarState = states.GetAvatarState(enemyAddress);
            }
            if (enemyAvatarState is null)
            {
                throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the opponent ({enemyAddress}) was failed to load.");
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get Enemy AvatarState: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            var weeklyArenaState = states.GetWeeklyArenaState(weeklyArenaAddress);

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get WeeklyArenaState ({Address}): {Elapsed}", addressesHex, weeklyArenaAddress, sw.Elapsed);
            sw.Restart();

            if (weeklyArenaState.Ended)
            {
                throw new WeeklyArenaStateAlreadyEndedException();
            }

            var costumeStatSheet = states.GetSheet <CostumeStatSheet>();

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get CostumeStatSheet: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            if (!weeklyArenaState.ContainsKey(avatarAddress))
            {
                var characterSheet = states.GetSheet <CharacterSheet>();
                weeklyArenaState.SetV2(avatarState, characterSheet, costumeStatSheet);
                sw.Stop();
                Log.Verbose("{AddressesHex}RankingBattle Set AvatarInfo: {Elapsed}", addressesHex, sw.Elapsed);
                sw.Restart();
            }

            var arenaInfo = weeklyArenaState[avatarAddress];

            if (arenaInfo.DailyChallengeCount <= 0)
            {
                throw new NotEnoughWeeklyArenaChallengeCountException(
                          addressesHex + NotEnoughWeeklyArenaChallengeCountException.BaseMessage);
            }

            if (!arenaInfo.Active)
            {
                arenaInfo.Activate();
            }

            if (!weeklyArenaState.ContainsKey(enemyAddress))
            {
                throw new WeeklyArenaStateNotContainsAvatarAddressException(addressesHex, enemyAddress);
            }

            var enemyArenaInfo = weeklyArenaState[enemyAddress];

            if (!enemyArenaInfo.Active)
            {
                enemyArenaInfo.Activate();
            }

            Log.Verbose("{WeeklyArenaStateAddress}", weeklyArenaState.address.ToHex());

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Validate ArenaInfo: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            ArenaInfo      = new ArenaInfo((Dictionary)weeklyArenaState[avatarAddress].Serialize());
            EnemyArenaInfo = new ArenaInfo((Dictionary)weeklyArenaState[enemyAddress].Serialize());
            var simulator = new RankingSimulator(
                ctx.Random,
                avatarState,
                enemyAvatarState,
                consumableIds,
                states.GetRankingSimulatorSheets(),
                StageId,
                arenaInfo,
                enemyArenaInfo,
                costumeStatSheet);

            simulator.SimulateV4();

            sw.Stop();
            Log.Verbose(
                "{AddressesHex}RankingBattle Simulate() with equipment:({Equipment}), costume:({Costume}): {Elapsed}",
                addressesHex,
                string.Join(",", simulator.Player.Equipments.Select(r => r.ItemId)),
                string.Join(",", simulator.Player.Costumes.Select(r => r.ItemId)),
                sw.Elapsed
                );

            Log.Verbose(
                "{AddressesHex}Execute RankingBattle({AvatarAddress}); result: {Result} event count: {EventCount}",
                addressesHex,
                avatarAddress,
                simulator.Log.result,
                simulator.Log.Count
                );
            sw.Restart();

            Result = simulator.Log;

            foreach (var itemBase in simulator.Reward.OrderBy(i => i.Id))
            {
                Log.Verbose(
                    "{AddressesHex}RankingBattle Add Reward Item({ItemBaseId}): {Elapsed}",
                    addressesHex,
                    itemBase.Id,
                    sw.Elapsed);
                avatarState.inventory.AddItem(itemBase);
            }

            states = states.SetState(weeklyArenaAddress, weeklyArenaState.Serialize());

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Serialize WeeklyArenaState: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            states = states
                     .SetState(inventoryAddress, avatarState.inventory.Serialize())
                     .SetState(worldInformationAddress, avatarState.worldInformation.Serialize())
                     .SetState(questListAddress, avatarState.questList.Serialize())
                     .SetState(avatarAddress, avatarState.SerializeV2());

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Serialize AvatarState: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            var ended = DateTimeOffset.UtcNow;

            Log.Verbose("{AddressesHex}RankingBattle Total Executed Time: {Elapsed}", addressesHex, ended - started);
            EnemyAvatarState = enemyAvatarState;
            return(states);
        }
Пример #7
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IActionContext ctx    = context;
            var            states = ctx.PreviousStates;

            if (ctx.Rehearsal)
            {
                return(states.SetState(ctx.Signer, MarkChanged)
                       .SetState(AvatarAddress, MarkChanged)
                       .SetState(WeeklyArenaAddress, MarkChanged)
                       .SetState(ctx.Signer, MarkChanged)
                       .MarkBalanceChanged(GoldCurrencyMock, ctx.Signer, WeeklyArenaAddress));
            }

            var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress, EnemyAddress);

            var sw = new Stopwatch();

            sw.Start();
            var started = DateTimeOffset.UtcNow;

            Log.Verbose(
                "{AddressesHex}RankingBattle exec started. costume: ({CostumeIds}), equipment: ({EquipmentIds})",
                addressesHex,
                string.Join(",", costumeIds),
                string.Join(",", equipmentIds)
                );

            if (AvatarAddress.Equals(EnemyAddress))
            {
                throw new InvalidAddressException($"{addressesHex}Aborted as the signer tried to battle for themselves.");
            }

            if (!states.TryGetAvatarState(ctx.Signer, AvatarAddress, out var avatarState))
            {
                throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load.");
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            avatarState.ValidateEquipments(equipmentIds, context.BlockIndex);
            avatarState.ValidateConsumable(consumableIds, context.BlockIndex);

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Validate Equipments: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world) ||
                world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard)
            {
                throw new NotEnoughClearedStageLevelException(
                          addressesHex,
                          GameConfig.RequireClearedStageLevel.ActionsInRankingBoard,
                          world.StageClearedId);
            }

            avatarState.EquipCostumes(new HashSet <int>(costumeIds));
            avatarState.EquipEquipments(equipmentIds);
            avatarState.ValidateCostume(new HashSet <int>(costumeIds));

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Equip Equipments: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            var enemyAvatarState = states.GetAvatarState(EnemyAddress);

            if (enemyAvatarState is null)
            {
                throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the opponent ({EnemyAddress}) was failed to load.");
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get Enemy AvatarState: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            var weeklyArenaState = states.GetWeeklyArenaState(WeeklyArenaAddress);

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get WeeklyArenaState ({Address}): {Elapsed}", addressesHex, WeeklyArenaAddress, sw.Elapsed);
            sw.Restart();

            if (weeklyArenaState.Ended)
            {
                throw new WeeklyArenaStateAlreadyEndedException(
                          addressesHex + WeeklyArenaStateAlreadyEndedException.BaseMessage);
            }

            if (!weeklyArenaState.ContainsKey(AvatarAddress))
            {
                throw new WeeklyArenaStateNotContainsAvatarAddressException(addressesHex, AvatarAddress);
            }

            var arenaInfo = weeklyArenaState[AvatarAddress];

            if (arenaInfo.DailyChallengeCount <= 0)
            {
                throw new NotEnoughWeeklyArenaChallengeCountException(
                          addressesHex + NotEnoughWeeklyArenaChallengeCountException.BaseMessage);
            }

            if (!arenaInfo.Active)
            {
                arenaInfo.Activate();
            }

            if (!weeklyArenaState.ContainsKey(EnemyAddress))
            {
                throw new WeeklyArenaStateNotContainsAvatarAddressException(addressesHex, EnemyAddress);
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Validate ArenaInfo: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            var costumeStatSheet = states.GetSheet <CostumeStatSheet>();

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get CostumeStatSheet: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            var simulator = new RankingSimulator(
                ctx.Random,
                avatarState,
                enemyAvatarState,
                consumableIds,
                states.GetRankingSimulatorSheets(),
                StageId,
                arenaInfo,
                weeklyArenaState[EnemyAddress],
                costumeStatSheet);

            simulator.Simulate();

            sw.Stop();
            Log.Verbose(
                "{AddressesHex}RankingBattle Simulate() with equipment:({Equipment}), costume:({Costume}): {Elapsed}",
                addressesHex,
                string.Join(",", simulator.Player.Equipments.Select(r => r.ItemId)),
                string.Join(",", simulator.Player.Costumes.Select(r => r.ItemId)),
                sw.Elapsed
                );

            Log.Verbose(
                "{AddressesHex}Execute RankingBattle({AvatarAddress}); result: {Result} event count: {EventCount}",
                addressesHex,
                AvatarAddress,
                simulator.Log.result,
                simulator.Log.Count
                );
            sw.Restart();

            Result = simulator.Log;

            foreach (var itemBase in simulator.Reward.OrderBy(i => i.Id))
            {
                Log.Verbose(
                    "{AddressesHex}RankingBattle Add Reward Item({ItemBaseId}): {Elapsed}",
                    addressesHex,
                    itemBase.Id,
                    sw.Elapsed);
                avatarState.inventory.AddItem(itemBase);
            }

            states = states.SetState(WeeklyArenaAddress, weeklyArenaState.Serialize());

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Serialize WeeklyArenaState: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            states = states.SetState(AvatarAddress, avatarState.Serialize());

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Serialize AvatarState: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            var ended = DateTimeOffset.UtcNow;

            Log.Verbose("{AddressesHex}RankingBattle Total Executed Time: {Elapsed}", addressesHex, ended - started);
            return(states);
        }
Пример #8
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IActionContext ctx                     = context;
            var            states                  = ctx.PreviousStates;
            var            inventoryAddress        = avatarAddress.Derive(LegacyInventoryKey);
            var            worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey);
            var            questListAddress        = avatarAddress.Derive(LegacyQuestListKey);

            if (ctx.Rehearsal)
            {
                return(states
                       .SetState(avatarAddress, MarkChanged)
                       .SetState(weeklyArenaAddress, MarkChanged)
                       .SetState(inventoryAddress, MarkChanged)
                       .SetState(worldInformationAddress, MarkChanged)
                       .SetState(questListAddress, MarkChanged));
            }

            // Avoid InvalidBlockStateRootHashException
            if (ctx.BlockIndex == 680341 && Id.Equals(new Guid("df37dbd8-5703-4dff-918b-ad22ee4c34c6")))
            {
                return(states);
            }

            var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress, enemyAddress);

            var sw = new Stopwatch();

            sw.Start();
            var started = DateTimeOffset.UtcNow;

            Log.Verbose(
                "{AddressesHex}RankingBattle exec started. costume: ({CostumeIds}), equipment: ({EquipmentIds})",
                addressesHex,
                string.Join(",", costumeIds),
                string.Join(",", equipmentIds)
                );

            if (avatarAddress.Equals(enemyAddress))
            {
                throw new InvalidAddressException($"{addressesHex}Aborted as the signer tried to battle for themselves.");
            }

            if (!states.TryGetAvatarStateV2(ctx.Signer, avatarAddress, out var avatarState, out bool migrationRequired))
            {
                throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load.");
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed);

            sw.Restart();
            var sheets = states.GetSheets(
                containRankingSimulatorSheets: true,
                sheetTypes: new[]
            {
                typeof(CharacterSheet),
                typeof(CostumeStatSheet),
            });

            sw.Stop();
            Log.Verbose("{AddressesHex}HAS Get Sheets: {Elapsed}", addressesHex, sw.Elapsed);

            sw.Restart();
            var items = equipmentIds.Concat(costumeIds);

            avatarState.ValidateEquipmentsV2(equipmentIds, context.BlockIndex);
            avatarState.ValidateCostume(costumeIds);

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Validate Equipments: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            avatarState.EquipItems(items);

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Equip Equipments: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world) ||
                world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard)
            {
                throw new NotEnoughClearedStageLevelException(
                          addressesHex,
                          GameConfig.RequireClearedStageLevel.ActionsInRankingBoard,
                          world.StageClearedId);
            }

            AvatarState enemyAvatarState;

            try
            {
                enemyAvatarState = states.GetAvatarStateV2(enemyAddress);
            }
            // BackWard compatible.
            catch (FailedLoadStateException)
            {
                enemyAvatarState = states.GetAvatarState(enemyAddress);
            }
            if (enemyAvatarState is null)
            {
                throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the opponent ({enemyAddress}) was failed to load.");
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get Enemy AvatarState: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            if (!states.TryGetState(weeklyArenaAddress, out Dictionary rawWeeklyArenaState))
            {
                return(states);
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get WeeklyArenaState ({Address}): {Elapsed}", addressesHex, weeklyArenaAddress, sw.Elapsed);
            sw.Restart();

            bool       arenaEnded     = rawWeeklyArenaState["ended"].ToBoolean();
            Dictionary weeklyArenaMap = (Dictionary)rawWeeklyArenaState["map"];

            if (arenaEnded)
            {
                throw new WeeklyArenaStateAlreadyEndedException();
            }

            var costumeStatSheet = sheets.GetSheet <CostumeStatSheet>();

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get CostumeStatSheet: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            IKey arenaKey = (IKey)avatarAddress.Serialize();

            if (!weeklyArenaMap.ContainsKey(arenaKey))
            {
                var characterSheet = sheets.GetSheet <CharacterSheet>();
                var newInfo        = new ArenaInfo(avatarState, characterSheet, costumeStatSheet, false);
                weeklyArenaMap =
                    (Dictionary)weeklyArenaMap.Add(arenaKey, newInfo.Serialize());
                sw.Stop();
                Log.Verbose("{AddressesHex}RankingBattle Set AvatarInfo: {Elapsed}", addressesHex, sw.Elapsed);
                sw.Restart();
            }

            var arenaInfo = new ArenaInfo((Dictionary)weeklyArenaMap[arenaKey]);

            if (arenaInfo.DailyChallengeCount <= 0)
            {
                throw new NotEnoughWeeklyArenaChallengeCountException(
                          addressesHex + NotEnoughWeeklyArenaChallengeCountException.BaseMessage);
            }

            if (!arenaInfo.Active)
            {
                arenaInfo.Activate();
            }

            IKey enemyKey = (IKey)enemyAddress.Serialize();

            if (!weeklyArenaMap.ContainsKey(enemyKey))
            {
                throw new WeeklyArenaStateNotContainsAvatarAddressException(addressesHex, enemyAddress);
            }

            var enemyArenaInfo = new ArenaInfo((Dictionary)weeklyArenaMap[enemyKey]);

            if (!enemyArenaInfo.Active)
            {
                enemyArenaInfo.Activate();
            }

            Log.Verbose("{WeeklyArenaStateAddress}", weeklyArenaAddress.ToHex());

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Validate ArenaInfo: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            ArenaInfo      = new ArenaInfo((Dictionary)weeklyArenaMap[arenaKey]);
            EnemyArenaInfo = new ArenaInfo((Dictionary)weeklyArenaMap[enemyKey]);
            var rankingSheets     = sheets.GetRankingSimulatorSheets();
            var player            = new Player(avatarState, rankingSheets);
            var enemyPlayerDigest = new EnemyPlayerDigest(enemyAvatarState);
            var simulator         = new RankingSimulator(
                ctx.Random,
                player,
                enemyPlayerDigest,
                new List <Guid>(),
                rankingSheets,
                StageId,
                arenaInfo,
                enemyArenaInfo,
                costumeStatSheet);

            simulator.Simulate();

            sw.Stop();
            Log.Verbose(
                "{AddressesHex}RankingBattle Simulate() with equipment:({Equipment}), costume:({Costume}): {Elapsed}",
                addressesHex,
                string.Join(",", simulator.Player.Equipments.Select(r => r.ItemId)),
                string.Join(",", simulator.Player.Costumes.Select(r => r.ItemId)),
                sw.Elapsed
                );

            Log.Verbose(
                "{AddressesHex}Execute RankingBattle({AvatarAddress}); result: {Result} event count: {EventCount}",
                addressesHex,
                avatarAddress,
                simulator.Log.result,
                simulator.Log.Count
                );
            sw.Restart();

            foreach (var itemBase in simulator.Reward.OrderBy(i => i.Id))
            {
                Log.Verbose(
                    "{AddressesHex}RankingBattle Add Reward Item({ItemBaseId}): {Elapsed}",
                    addressesHex,
                    itemBase.Id,
                    sw.Elapsed);
                avatarState.inventory.AddItem(itemBase);
            }

            var arenaMapDict = new Dictionary <IKey, IValue>();

            foreach (var kv in weeklyArenaMap)
            {
                var key   = kv.Key;
                var value = kv.Value;
                if (key.Equals(arenaKey))
                {
                    value = arenaInfo.Serialize();
                }

                if (key.Equals(enemyKey))
                {
                    value = enemyArenaInfo.Serialize();
                }

                arenaMapDict[key] = value;
            }

            var weeklyArenaDict = new Dictionary <IKey, IValue>();

            foreach (var kv in rawWeeklyArenaState)
            {
                weeklyArenaDict[kv.Key] = kv.Key.Equals((Text)"map")
                    ? new Dictionary(arenaMapDict)
                    : kv.Value;
            }

            states = states.SetState(weeklyArenaAddress, new Dictionary(weeklyArenaDict));

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Serialize WeeklyArenaState: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            states = states
                     .SetState(inventoryAddress, avatarState.inventory.Serialize())
                     .SetState(questListAddress, avatarState.questList.Serialize());

            if (migrationRequired)
            {
                states = states
                         .SetState(worldInformationAddress, avatarState.worldInformation.Serialize())
                         .SetState(avatarAddress, avatarState.SerializeV2());
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Serialize AvatarState: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            var ended = DateTimeOffset.UtcNow;

            Log.Verbose("{AddressesHex}RankingBattle Total Executed Time: {Elapsed}", addressesHex, ended - started);
            EnemyPlayerDigest = enemyPlayerDigest;
            return(states);
        }
Пример #9
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IActionContext ctx    = context;
            var            states = ctx.PreviousStates;

            if (ctx.Rehearsal)
            {
                return(states.SetState(ctx.Signer, MarkChanged)
                       .SetState(AvatarAddress, MarkChanged)
                       .SetState(WeeklyArenaAddress, MarkChanged)
                       .SetState(ctx.Signer, MarkChanged)
                       .MarkBalanceChanged(GoldCurrencyMock, ctx.Signer, WeeklyArenaAddress));
            }

            if (AvatarAddress.Equals(EnemyAddress))
            {
                return(LogError(context, "Aborted as the signer tried to battle for themselves."));
            }

            if (!states.TryGetAgentAvatarStates(ctx.Signer, AvatarAddress, out var agentState,
                                                out var avatarState))
            {
                return(LogError(context, "Aborted as the avatar state of the signer was failed to load."));
            }

            // 도전자의 장비가 유효한지 검사한다.
            // 피도전자의 장비도 검사해야 하는가는 모르겠다. 이후에 필요하다면 추가하는 것으로 한다.
            if (!avatarState.ValidateEquipments(equipmentIds, context.BlockIndex))
            {
                // 장비가 유효하지 않은 에러.
                return(LogError(context, "Aborted as the equipment is invalid."));
            }

            if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world))
            {
                return(LogError(context, "Aborted as the WorldInformation was failed to load or not cleared yet."));
            }

            if (world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard)
            {
                // 스테이지 클리어 부족 에러.
                return(LogError(
                           context,
                           "Aborted as the signer is not cleared the minimum stage level required to battle with other players yet: {ClearedLevel} < {RequiredLevel}.",
                           world.StageClearedId,
                           GameConfig.RequireClearedStageLevel.ActionsInRankingBoard
                           ));
            }

            avatarState.EquipCostumes(costumeIds);
            avatarState.EquipEquipments(equipmentIds);

            var enemyAvatarState = states.GetAvatarState(EnemyAddress);

            if (enemyAvatarState is null)
            {
                return(LogError(
                           context,
                           "Aborted as the avatar state of the opponent ({OpponentAddress}) was failed to load.",
                           EnemyAddress
                           ));
            }

            var weeklyArenaState = states.GetWeeklyArenaState(WeeklyArenaAddress);

            //FIXME 오류던지게 고쳐야함
            if (weeklyArenaState.Ended)
            {
                return(LogError(context, "Aborted as the weekly arena state already ended."));
            }

            if (!weeklyArenaState.ContainsKey(AvatarAddress))
            {
                return(LogError(context, "Aborted as the weekly arena state was failed to load."));
            }

            var arenaInfo = weeklyArenaState[AvatarAddress];

            if (arenaInfo.DailyChallengeCount <= 0)
            {
                return(LogError(context, "Aborted as the arena state reached the daily limit."));
            }

            if (!arenaInfo.Active)
            {
                FungibleAssetValue agentBalance = states.GetBalance(ctx.Signer, states.GetGoldCurrency());

                if (agentBalance >= new FungibleAssetValue(agentBalance.Currency, EntranceFee, 0))
                {
                    states = states.TransferAsset(
                        ctx.Signer,
                        WeeklyArenaAddress,
                        new FungibleAssetValue(
                            states.GetGoldCurrency(),
                            EntranceFee,
                            0
                            )
                        );
                    arenaInfo.Activate();
                }
                else
                {
                    return(LogError(
                               context,
                               "Aborted as the signer's balance ({Balance}) is insufficient to pay entrance fee/stake ({EntranceFee}).",
                               agentBalance,
                               EntranceFee
                               ));
                }
            }

            if (!weeklyArenaState.ContainsKey(EnemyAddress))
            {
                return(LogError(
                           context,
                           "Aborted as the opponent ({OpponentAddress}) is not registered in the weekly arena state.",
                           EnemyAddress
                           ));
            }

            Log.Debug(weeklyArenaState.address.ToHex());

            var tableSheetState = TableSheetsState.FromActionContext(ctx);
            var tableSheets     = TableSheets.FromTableSheetsState(tableSheetState);

            var simulator = new RankingSimulator(
                ctx.Random,
                avatarState,
                enemyAvatarState,
                consumableIds,
                tableSheets,
                StageId);

            simulator.Simulate();

            simulator.Log.diffScore = arenaInfo.Update(avatarState, weeklyArenaState[EnemyAddress], simulator.Result);
            simulator.Log.score     = arenaInfo.Score;

            Result = simulator.Log;

            foreach (var itemBase in simulator.Reward)
            {
                avatarState.inventory.AddItem(itemBase);
            }

            return(states
                   .SetState(ctx.Signer, agentState.Serialize())
                   .SetState(WeeklyArenaAddress, weeklyArenaState.Serialize())
                   .SetState(AvatarAddress, avatarState.Serialize()));
        }
Пример #10
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IActionContext ctx                     = context;
            var            states                  = ctx.PreviousStates;
            var            inventoryAddress        = avatarAddress.Derive(LegacyInventoryKey);
            var            worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey);
            var            questListAddress        = avatarAddress.Derive(LegacyQuestListKey);

            if (ctx.Rehearsal)
            {
                return(states
                       .SetState(avatarAddress, MarkChanged)
                       .SetState(weeklyArenaAddress, MarkChanged)
                       .SetState(inventoryAddress, MarkChanged)
                       .SetState(worldInformationAddress, MarkChanged)
                       .SetState(questListAddress, MarkChanged));
            }

            // Avoid InvalidBlockStateRootHashException
            if (ctx.BlockIndex == 680341 && Id.Equals(new Guid("df37dbd8-5703-4dff-918b-ad22ee4c34c6")))
            {
                return(states);
            }

            var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress, enemyAddress);

            var sw = new Stopwatch();

            sw.Start();
            var started = DateTimeOffset.UtcNow;

            Log.Verbose(
                "{AddressesHex}RankingBattle exec started. costume: ({CostumeIds}), equipment: ({EquipmentIds})",
                addressesHex,
                string.Join(",", costumeIds),
                string.Join(",", equipmentIds)
                );

            if (avatarAddress.Equals(enemyAddress))
            {
                throw new InvalidAddressException($"{addressesHex}Aborted as the signer tried to battle for themselves.");
            }

            if (!states.TryGetAvatarStateV2(ctx.Signer, avatarAddress, out var avatarState, out bool migrationRequired))
            {
                throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load.");
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed);

            sw.Restart();
            var sheets = states.GetSheets(
                containRankingSimulatorSheets: true,
                sheetTypes: new[]
            {
                typeof(CharacterSheet),
                typeof(CostumeStatSheet),
            });

            sw.Stop();
            Log.Verbose("{AddressesHex}HAS Get Sheets: {Elapsed}", addressesHex, sw.Elapsed);

            sw.Restart();
            var items = equipmentIds.Concat(costumeIds);

            avatarState.ValidateEquipmentsV2(equipmentIds, context.BlockIndex);
            avatarState.ValidateCostume(costumeIds);

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Validate Equipments: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            avatarState.EquipItems(items);

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Equip Equipments: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world) ||
                world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard)
            {
                throw new NotEnoughClearedStageLevelException(
                          addressesHex,
                          GameConfig.RequireClearedStageLevel.ActionsInRankingBoard,
                          world.StageClearedId);
            }

            AvatarState enemyAvatarState;

            try
            {
                enemyAvatarState = states.GetAvatarStateV2(enemyAddress);
            }
            // BackWard compatible.
            catch (FailedLoadStateException)
            {
                enemyAvatarState = states.GetAvatarState(enemyAddress);
            }
            if (enemyAvatarState is null)
            {
                throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the opponent ({enemyAddress}) was failed to load.");
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get Enemy AvatarState: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            var costumeStatSheet = sheets.GetSheet <CostumeStatSheet>();

            if (!states.TryGetState(weeklyArenaAddress, out Dictionary rawWeeklyArenaState))
            {
                return(states);
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}RankingBattle Get WeeklyArenaState ({Address}): {Elapsed}", addressesHex, weeklyArenaAddress, sw.Elapsed);
            sw.Restart();

            bool arenaEnded = rawWeeklyArenaState["ended"].ToBoolean();

            if (arenaEnded)
            {
                throw new WeeklyArenaStateAlreadyEndedException();
            }

            if (context.BlockIndex >= UpdateTargetBlockIndex)
            {
                // Run updated model
                var       arenaInfoAddress = weeklyArenaAddress.Derive(avatarAddress.ToByteArray());
                ArenaInfo arenaInfo;
                var       characterSheet     = sheets.GetSheet <CharacterSheet>();
                var       addressListAddress = weeklyArenaAddress.Derive("address_list");
                bool      listCheck          = false;
                if (!states.TryGetState(arenaInfoAddress, out Dictionary rawArenaInfo))
                {
                    arenaInfo    = new ArenaInfo(avatarState, characterSheet, costumeStatSheet, true);
                    listCheck    = true;
                    rawArenaInfo = (Dictionary)arenaInfo.Serialize();
                }
                else
                {
                    arenaInfo = new ArenaInfo(rawArenaInfo);
                }

                var       enemyInfoAddress = weeklyArenaAddress.Derive(enemyAddress.ToByteArray());
                ArenaInfo enemyInfo;
                if (!states.TryGetState(enemyInfoAddress, out Dictionary rawEnemyInfo))
                {
                    enemyInfo = new ArenaInfo(enemyAvatarState, characterSheet, costumeStatSheet,
                                              true);
                    listCheck    = true;
                    rawEnemyInfo = (Dictionary)enemyInfo.Serialize();
                }
                else
                {
                    enemyInfo = new ArenaInfo(rawEnemyInfo);
                }

                if (arenaInfo.DailyChallengeCount <= 0)
                {
                    throw new NotEnoughWeeklyArenaChallengeCountException(
                              addressesHex + NotEnoughWeeklyArenaChallengeCountException.BaseMessage);
                }

                ArenaInfo      = new ArenaInfo(rawArenaInfo);
                EnemyArenaInfo = new ArenaInfo(rawEnemyInfo);
                var rankingSheets     = sheets.GetRankingSimulatorSheets();
                var player            = new Player(avatarState, rankingSheets);
                var enemyPlayerDigest = new EnemyPlayerDigest(enemyAvatarState);
                var simulator         = new RankingSimulator(
                    ctx.Random,
                    player,
                    enemyPlayerDigest,
                    new List <Guid>(),
                    rankingSheets,
                    StageId,
                    arenaInfo,
                    enemyInfo,
                    costumeStatSheet);

                simulator.Simulate();

                sw.Stop();
                Log.Verbose(
                    "{AddressesHex}RankingBattle Simulate() with equipment:({Equipment}), costume:({Costume}): {Elapsed}",
                    addressesHex,
                    string.Join(",", simulator.Player.Equipments.Select(r => r.ItemId)),
                    string.Join(",", simulator.Player.Costumes.Select(r => r.ItemId)),
                    sw.Elapsed
                    );

                Log.Verbose(
                    "{AddressesHex}Execute RankingBattle({AvatarAddress}); result: {Result} event count: {EventCount}",
                    addressesHex,
                    avatarAddress,
                    simulator.Log.result,
                    simulator.Log.Count
                    );
                sw.Restart();

                foreach (var itemBase in simulator.Reward.OrderBy(i => i.Id))
                {
                    Log.Verbose(
                        "{AddressesHex}RankingBattle Add Reward Item({ItemBaseId}): {Elapsed}",
                        addressesHex,
                        itemBase.Id,
                        sw.Elapsed);
                    avatarState.inventory.AddItem(itemBase);
                }

                sw.Stop();
                Log.Verbose("{AddressesHex}RankingBattle Serialize WeeklyArenaState: {Elapsed}", addressesHex, sw.Elapsed);
                sw.Restart();

                states = states
                         .SetState(inventoryAddress, avatarState.inventory.Serialize())
                         .SetState(arenaInfoAddress, arenaInfo.Serialize())
                         .SetState(enemyInfoAddress, enemyInfo.Serialize())
                         .SetState(questListAddress, avatarState.questList.Serialize());

                if (migrationRequired)
                {
                    states = states
                             .SetState(worldInformationAddress, avatarState.worldInformation.Serialize())
                             .SetState(avatarAddress, avatarState.SerializeV2());
                }

                if (listCheck)
                {
                    var addressList = states.TryGetState(addressListAddress, out List rawAddressList)
                        ? rawAddressList.ToList(StateExtensions.ToAddress)
                        : new List <Address>();

                    if (!addressList.Contains(avatarAddress))
                    {
                        addressList.Add(avatarAddress);
                    }

                    if (!addressList.Contains(enemyAddress))
                    {
                        addressList.Add(enemyAddress);
                    }

                    states = states.SetState(addressListAddress,
                                             addressList.Aggregate(List.Empty,
                                                                   (current, address) => current.Add(address.Serialize())));
                }
                sw.Stop();
                Log.Verbose("{AddressesHex}RankingBattle Serialize AvatarState: {Elapsed}", addressesHex, sw.Elapsed);
                sw.Restart();

                var ended = DateTimeOffset.UtcNow;
                Log.Verbose("{AddressesHex}RankingBattle Total Executed Time: {Elapsed}", addressesHex, ended - started);
                EnemyPlayerDigest = enemyPlayerDigest;
                return(states);
            }
            // Run Backward compatible
            return(BackwardCompatibleExecute(rawWeeklyArenaState, sheets, avatarState, costumeStatSheet, sw, addressesHex, enemyAvatarState, ctx, states, inventoryAddress, questListAddress, migrationRequired, worldInformationAddress, started));
        }