示例#1
0
        private void DummyBattle(int stageId)
        {
            Find <BattleResult>()?.Close();
            Find <Menu>()?.Close();
            Find <Menu>()?.ShowWorld();

            if (!Game.Game.instance.TableSheets.WorldSheet.TryGetByStageId(stageId, out var worldRow))
            {
                throw new KeyNotFoundException($"WorldSheet.TryGetByStageId() {nameof(stageId)}({stageId})");
            }

            var tableSheets = Game.Game.instance.TableSheets;
            var simulator   = new StageSimulator(
                new DebugRandom(),
                States.Instance.CurrentAvatarState,
                new List <Guid>(),
                worldRow.Id,
                stageId,
                tableSheets.GetStageSimulatorSheets(),
                _selectedSkill
                );

            simulator.Simulate();
            simulator.Log.result = _result;

            var stage = Game.Game.instance.Stage;

            stage.PlayStage(simulator.Log);

            Close();
        }
示例#2
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IActionContext ctx    = context;
            var            states = ctx.PreviousStates;

            if (ctx.Rehearsal)
            {
                states = states.SetState(RankingMapAddress, MarkChanged);
                states = states.SetState(avatarAddress, MarkChanged);
                states = states.SetState(WeeklyArenaAddress, MarkChanged);
                return(states.SetState(ctx.Signer, MarkChanged));
            }

            var sw = new Stopwatch();

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

            Log.Debug("HAS exec started.");

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

            sw.Stop();
            Log.Debug("HAS Get AgentAvatarStates: {Elapsed}", sw.Elapsed);

            sw.Restart();

            if (avatarState.RankingMapAddress != RankingMapAddress)
            {
                throw new InvalidAddressException("Invalid ranking map address");
            }

            // worldId와 stageId가 유효한지 확인합니다.
            var worldSheet = states.GetSheet <WorldSheet>();

            if (!worldSheet.TryGetValue(worldId, out var worldRow, false))
            {
                throw new SheetRowNotFoundException(nameof(WorldSheet), worldId);
            }

            if (stageId < worldRow.StageBegin ||
                stageId > worldRow.StageEnd)
            {
                throw new SheetRowColumnException(
                          $"{worldId} world is not contains {worldRow.Id} stage: " +
                          $"{worldRow.StageBegin}-{worldRow.StageEnd}");
            }

            var stageSheet = states.GetSheet <StageSheet>();

            if (!stageSheet.TryGetValue(stageId, out var stageRow))
            {
                throw new SheetRowNotFoundException(nameof(StageSheet), stageId);
            }

            var worldInformation = avatarState.worldInformation;

            if (!worldInformation.TryGetWorld(worldId, out var world))
            {
                // NOTE: Add new World from WorldSheet
                worldInformation.AddAndUnlockNewWorld(worldRow, ctx.BlockIndex, worldSheet);
            }

            if (!world.IsUnlocked)
            {
                throw new InvalidWorldException($"{worldId} is locked.");
            }

            if (world.StageBegin != worldRow.StageBegin ||
                world.StageEnd != worldRow.StageEnd)
            {
                worldInformation.UpdateWorld(worldRow);
            }

            if (world.IsStageCleared && stageId > world.StageClearedId + 1 ||
                !world.IsStageCleared && stageId != world.StageBegin)
            {
                throw new InvalidStageException(
                          $"Aborted as the stage ({worldId}/{stageId}) is not cleared; " +
                          $"cleared stage: {world.StageClearedId}"
                          );
            }

            avatarState.ValidateEquipments(equipments, context.BlockIndex);
            avatarState.ValidateConsumable(foods, context.BlockIndex);
            avatarState.ValidateCostume(new HashSet <int>(costumes));

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

            sw.Restart();
            if (avatarState.actionPoint < stageRow.CostAP)
            {
                throw new NotEnoughActionPointException(
                          $"Aborted due to insufficient action point: " +
                          $"{avatarState.actionPoint} < {stageRow.CostAP}"
                          );
            }

            avatarState.actionPoint -= stageRow.CostAP;

            avatarState.EquipCostumes(new HashSet <int>(costumes));

            avatarState.EquipEquipments(equipments);
            sw.Stop();
            Log.Debug("HAS Unequip items: {Elapsed}", sw.Elapsed);

            sw.Restart();
            var characterSheet = states.GetSheet <CharacterSheet>();
            var simulator      = new StageSimulator(
                ctx.Random,
                avatarState,
                foods,
                worldId,
                stageId,
                states.GetStageSimulatorSheets(),
                costumeStatSheet
                );

            sw.Stop();
            Log.Debug("HAS Initialize Simulator: {Elapsed}", sw.Elapsed);

            sw.Restart();
            simulator.Simulate();
            sw.Stop();
            Log.Debug("HAS Simulator.Simulate(): {Elapsed}", sw.Elapsed);

            Log.Debug(
                "Execute HackAndSlash({AvatarAddress}); worldId: {WorldId}, stageId: {StageId}, result: {Result}, " +
                "clearWave: {ClearWave}, totalWave: {TotalWave}",
                avatarAddress,
                worldId,
                stageId,
                simulator.Log.result,
                simulator.Log.clearedWaveNumber,
                simulator.Log.waveCount
                );

            sw.Restart();
            if (simulator.Log.IsClear)
            {
                var worldUnlockSheet = states.GetSheet <WorldUnlockSheet>();
                simulator.Player.worldInformation.ClearStage(
                    worldId,
                    stageId,
                    ctx.BlockIndex,
                    worldSheet,
                    worldUnlockSheet
                    );
            }

            sw.Stop();
            Log.Debug("HAS ClearStage: {Elapsed}", sw.Elapsed);

            sw.Restart();
            avatarState.Update(simulator);

            var materialSheet = states.GetSheet <MaterialItemSheet>();

            avatarState.UpdateQuestRewards(materialSheet);

            avatarState.updatedAt = ctx.BlockIndex;
            states = states.SetState(avatarAddress, avatarState.Serialize());

            sw.Stop();
            Log.Debug("HAS Set AvatarState: {Elapsed}", sw.Elapsed);

            sw.Restart();
            if (states.TryGetState(RankingMapAddress, out Dictionary d) && simulator.Log.IsClear)
            {
                var ranking = new RankingMapState(d);
                ranking.Update(avatarState);

                sw.Stop();
                Log.Debug("HAS Update RankingState: {Elapsed}", sw.Elapsed);
                sw.Restart();

                var serialized = ranking.Serialize();

                sw.Stop();
                Log.Debug("HAS Serialize RankingState: {Elapsed}", sw.Elapsed);
                sw.Restart();
                states = states.SetState(RankingMapAddress, serialized);
            }

            sw.Stop();
            Log.Debug("HAS Set RankingState: {Elapsed}", sw.Elapsed);

            sw.Restart();
            if (simulator.Log.stageId >= GameConfig.RequireClearedStageLevel.ActionsInRankingBoard &&
                simulator.Log.IsClear &&
                states.TryGetState(WeeklyArenaAddress, out Dictionary weeklyDict))
            {
                var weekly = new WeeklyArenaState(weeklyDict);
                if (!weekly.Ended)
                {
                    if (weekly.ContainsKey(avatarAddress))
                    {
                        var info = weekly[avatarAddress];
                        info.Update(avatarState, characterSheet, costumeStatSheet);
                        weekly.Update(info);
                    }
                    else
                    {
                        weekly.SetV2(avatarState, characterSheet, costumeStatSheet);
                    }

                    sw.Stop();
                    Log.Debug("HAS Update WeeklyArenaState: {Elapsed}", sw.Elapsed);

                    sw.Restart();
                    var weeklySerialized = weekly.Serialize();
                    sw.Stop();
                    Log.Debug("HAS Serialize RankingState: {Elapsed}", sw.Elapsed);

                    states = states.SetState(weekly.address, weeklySerialized);
                }
            }

            Result = simulator.Log;

            var ended = DateTimeOffset.UtcNow;

            Log.Debug("HAS Total Executed Time: {Elapsed}", ended - started);
            return(states);
        }
示例#3
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IActionContext ctx    = context;
            var            states = ctx.PreviousStates;

            if (ctx.Rehearsal)
            {
                states = states.SetState(RankingMapAddress, MarkChanged);
                states = states.SetState(avatarAddress, MarkChanged);
                return(states.SetState(WeeklyArenaAddress, MarkChanged));
            }

            var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress);

            var sw = new Stopwatch();

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

            Log.Verbose("{AddressesHex}Mimisbrunnr exec started", addressesHex);

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

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

            sw.Restart();

            if (avatarState.RankingMapAddress != RankingMapAddress)
            {
                throw new InvalidAddressException($"{addressesHex}Invalid ranking map address");
            }

            var worldSheet       = states.GetSheet <WorldSheet>();
            var worldUnlockSheet = states.GetSheet <WorldUnlockSheet>();

            if (!worldSheet.TryGetValue(worldId, out var worldRow, false))
            {
                throw new SheetRowNotFoundException(nameof(WorldSheet), worldId);
            }

            if (stageId < worldRow.StageBegin ||
                stageId > worldRow.StageEnd)
            {
                throw new SheetRowColumnException(
                          $"{addressesHex}{worldId} world is not contains {worldRow.Id} stage: " +
                          $"{worldRow.StageBegin}-{worldRow.StageEnd}");
            }

            var stageSheet = states.GetSheet <StageSheet>();

            if (!stageSheet.TryGetValue(stageId, out var stageRow))
            {
                throw new SheetRowNotFoundException(addressesHex, nameof(StageSheet), stageId);
            }

            var worldInformation = avatarState.worldInformation;

            if (!worldInformation.TryGetWorld(worldId, out var world))
            {
                // NOTE: Add new World from WorldSheet
                worldInformation.AddAndUnlockMimisbrunnrWorld(worldRow, ctx.BlockIndex, worldSheet, worldUnlockSheet);
                if (!worldInformation.TryGetWorld(worldId, out world))
                {
                    // Do nothing.
                }
            }

            if (!world.IsUnlocked)
            {
                var worldUnlockSheetRow = worldUnlockSheet.OrderedList.FirstOrDefault(row => row.WorldIdToUnlock == worldId);
                if (!(worldUnlockSheetRow is null) &&
                    worldInformation.IsWorldUnlocked(worldUnlockSheetRow.WorldId) &&
                    worldInformation.IsStageCleared(worldUnlockSheetRow.StageId))
                {
                    worldInformation.UnlockWorld(worldId, ctx.BlockIndex, worldSheet);
                    if (!worldInformation.TryGetWorld(worldId, out world))
                    {
                        // Do nothing.
                    }
                }
            }

            if (!world.IsUnlocked)
            {
                throw new InvalidWorldException($"{addressesHex}{worldId} is locked.");
            }

            if (world.StageBegin != worldRow.StageBegin ||
                world.StageEnd != worldRow.StageEnd)
            {
                worldInformation.UpdateWorld(worldRow);
            }

            if (world.IsStageCleared && stageId > world.StageClearedId + 1 ||
                !world.IsStageCleared && stageId != world.StageBegin)
            {
                throw new InvalidStageException(
                          $"{addressesHex}Aborted as the stage ({worldId}/{stageId}) is not cleared; " +
                          $"cleared stage: {world.StageClearedId}"
                          );
            }

            sw.Restart();
            var mimisbrunnrSheet = states.GetSheet <MimisbrunnrSheet>();

            if (!mimisbrunnrSheet.TryGetValue(stageId, out var mimisbrunnrSheetRow))
            {
                throw new SheetRowNotFoundException(addressesHex, "MimisbrunnrSheet", stageId);
            }

            foreach (var equipmentId in equipments)
            {
                if (avatarState.inventory.TryGetNonFungibleItem(equipmentId, out ItemUsable itemUsable))
                {
                    var elementalType = ((Equipment)itemUsable).ElementalType;
                    if (!mimisbrunnrSheetRow.ElementalTypes.Exists(x => x == elementalType))
                    {
                        throw new InvalidElementalException(
                                  $"{addressesHex}ElementalType of {equipmentId} does not match.");
                    }
                }
            }
            sw.Stop();
            Log.Verbose("{AddressesHex}Mimisbrunnr Check Equipments ElementalType: {Elapsed}", addressesHex, sw.Elapsed);

            avatarState.ValidateEquipments(equipments, context.BlockIndex);
            avatarState.ValidateConsumable(foods, context.BlockIndex);
            avatarState.ValidateCostume(costumes);

            sw.Restart();
            if (avatarState.actionPoint < stageRow.CostAP)
            {
                throw new NotEnoughActionPointException(
                          $"{addressesHex}Aborted due to insufficient action point: " +
                          $"{avatarState.actionPoint} < {stageRow.CostAP}"
                          );
            }
            avatarState.actionPoint -= stageRow.CostAP;
            var equippableItem = new List <Guid>();

            equippableItem.AddRange(costumes);
            equippableItem.AddRange(equipments);
            avatarState.EquipItems(equippableItem);
            sw.Stop();
            Log.Verbose("{AddressesHex}Mimisbrunnr Unequip items: {Elapsed}", addressesHex, sw.Elapsed);

            sw.Restart();
            var costumeStatSheet = states.GetSheet <CostumeStatSheet>();
            var simulator        = new StageSimulator(
                ctx.Random,
                avatarState,
                foods,
                worldId,
                stageId,
                states.GetStageSimulatorSheets(),
                costumeStatSheet
                );

            sw.Stop();
            Log.Verbose("{AddressesHex}Mimisbrunnr Initialize Simulator: {Elapsed}", addressesHex, sw.Elapsed);

            sw.Restart();
            simulator.Simulate();
            sw.Stop();
            Log.Verbose("{AddressesHex}Mimisbrunnr Simulator.Simulate(): {Elapsed}", addressesHex, sw.Elapsed);

            Log.Verbose(
                "{AddressesHex}Execute Mimisbrunnr({AvatarAddress}); worldId: {WorldId}, stageId: {StageId}, result: {Result}, " +
                "clearWave: {ClearWave}, totalWave: {TotalWave}",
                addressesHex,
                avatarAddress,
                worldId,
                stageId,
                simulator.Log.result,
                simulator.Log.clearedWaveNumber,
                simulator.Log.waveCount
                );

            sw.Restart();
            if (simulator.Log.IsClear)
            {
                simulator.Player.worldInformation.ClearStage(
                    worldId,
                    stageId,
                    ctx.BlockIndex,
                    worldSheet,
                    worldUnlockSheet
                    );
            }
            sw.Stop();
            Log.Verbose("{AddressesHex}Mimisbrunnr ClearStage: {Elapsed}", addressesHex, sw.Elapsed);

            sw.Restart();
            avatarState.Update(simulator);

            var materialSheet = states.GetSheet <MaterialItemSheet>();

            avatarState.UpdateQuestRewards(materialSheet);

            avatarState.updatedAt = ctx.BlockIndex;
            avatarState.mailBox.CleanUp();
            states = states.SetState(avatarAddress, avatarState.Serialize());

            sw.Stop();
            Log.Verbose("{AddressesHex}Mimisbrunnr Set AvatarState: {Elapsed}", addressesHex, sw.Elapsed);

            sw.Restart();
            if (states.TryGetState(RankingMapAddress, out Dictionary d) && simulator.Log.IsClear)
            {
                var ranking = new RankingMapState(d);
                ranking.Update(avatarState);

                sw.Stop();
                Log.Verbose("{AddressesHex}Mimisbrunnr Update RankingState: {Elapsed}", addressesHex, sw.Elapsed);
                sw.Restart();

                var serialized = ranking.Serialize();

                sw.Stop();
                Log.Verbose("{AddressesHex}Mimisbrunnr Serialize RankingState: {Elapsed}", addressesHex, sw.Elapsed);
                sw.Restart();
                states = states.SetState(RankingMapAddress, serialized);
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}Mimisbrunnr Set RankingState: {Elapsed}", addressesHex, sw.Elapsed);

            sw.Restart();
            if (simulator.Log.stageId >= GameConfig.RequireClearedStageLevel.ActionsInRankingBoard &&
                simulator.Log.IsClear &&
                states.TryGetState(WeeklyArenaAddress, out Dictionary weeklyDict))
            {
                var weekly = new WeeklyArenaState(weeklyDict);
                if (!weekly.Ended)
                {
                    var characterSheet = states.GetSheet <CharacterSheet>();
                    if (weekly.ContainsKey(avatarAddress))
                    {
                        var info = weekly[avatarAddress];
                        info.Update(avatarState, characterSheet, costumeStatSheet);
                        weekly.Update(info);
                    }
                    else
                    {
                        weekly.SetV2(avatarState, characterSheet, costumeStatSheet);
                    }

                    sw.Stop();
                    Log.Verbose("{AddressesHex}Mimisbrunnr Update WeeklyArenaState: {Elapsed}", addressesHex, sw.Elapsed);

                    sw.Restart();
                    var weeklySerialized = weekly.Serialize();
                    sw.Stop();
                    Log.Verbose("{AddressesHex}Mimisbrunnr Serialize RankingState: {Elapsed}", addressesHex, sw.Elapsed);

                    states = states.SetState(weekly.address, weeklySerialized);
                }
            }

            Result = simulator.Log;

            var ended = DateTimeOffset.UtcNow;

            Log.Verbose("{AddressesHex}Mimisbrunnr Total Executed Time: {Elapsed}", addressesHex, ended - started);
            return(states);
        }
示例#4
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)
            {
                states = states.SetState(rankingMapAddress, MarkChanged);
                states = states.SetState(avatarAddress, MarkChanged);
                states = states
                         .SetState(inventoryAddress, MarkChanged)
                         .SetState(worldInformationAddress, MarkChanged)
                         .SetState(questListAddress, MarkChanged);
                return(states.SetState(ctx.Signer, MarkChanged));
            }

            var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress);

            var sw = new Stopwatch();

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

            Log.Verbose("{AddressesHex}HAS exec started", addressesHex);

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

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

            if (avatarState.RankingMapAddress != rankingMapAddress)
            {
                throw new InvalidAddressException($"{addressesHex}Invalid ranking map address");
            }

            var worldSheet = states.GetSheet <WorldSheet>();

            if (!worldSheet.TryGetValue(worldId, out var worldRow, false))
            {
                throw new SheetRowNotFoundException(addressesHex, nameof(WorldSheet), worldId);
            }

            if (stageId < worldRow.StageBegin ||
                stageId > worldRow.StageEnd)
            {
                throw new SheetRowColumnException(
                          $"{addressesHex}{worldId} world is not contains {worldRow.Id} stage: " +
                          $"{worldRow.StageBegin}-{worldRow.StageEnd}");
            }

            var stageSheet = states.GetSheet <StageSheet>();

            if (!stageSheet.TryGetValue(stageId, out var stageRow))
            {
                throw new SheetRowNotFoundException(addressesHex, nameof(StageSheet), stageId);
            }

            var worldInformation = avatarState.worldInformation;

            if (!worldInformation.TryGetWorld(worldId, out var world))
            {
                // NOTE: Add new World from WorldSheet
                worldInformation.AddAndUnlockNewWorld(worldRow, ctx.BlockIndex, worldSheet);
            }

            if (!world.IsUnlocked)
            {
                throw new InvalidWorldException($"{addressesHex}{worldId} is locked.");
            }

            if (world.StageBegin != worldRow.StageBegin ||
                world.StageEnd != worldRow.StageEnd)
            {
                worldInformation.UpdateWorld(worldRow);
            }

            if (world.IsStageCleared && stageId > world.StageClearedId + 1 ||
                !world.IsStageCleared && stageId != world.StageBegin)
            {
                throw new InvalidStageException(
                          $"{addressesHex}Aborted as the stage ({worldId}/{stageId}) is not cleared; " +
                          $"cleared stage: {world.StageClearedId}"
                          );
            }

            if (worldId == GameConfig.MimisbrunnrWorldId)
            {
                throw new InvalidWorldException($"{addressesHex}{worldId} can't execute HackAndSlash action.");
            }

            avatarState.ValidateEquipmentsV2(equipments, context.BlockIndex);
            avatarState.ValidateConsumable(foods, context.BlockIndex);
            avatarState.ValidateCostume(costumes);

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

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

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

            if (playCount <= 0)
            {
                throw new PlayCountIsZeroException($"{addressesHex}playCount must be greater than 0. " +
                                                   $"current playCount : {playCount}");
            }

            var totalCostActionPoint = stageRow.CostAP * playCount;

            if (avatarState.actionPoint < totalCostActionPoint)
            {
                throw new NotEnoughActionPointException(
                          $"{addressesHex}Aborted due to insufficient action point: " +
                          $"{avatarState.actionPoint} < totalAP({totalCostActionPoint}) = cost({stageRow.CostAP}) * boostCount({playCount})"
                          );
            }

            avatarState.actionPoint -= totalCostActionPoint;

            var items = equipments.Concat(costumes);

            avatarState.EquipItems(items);
            sw.Stop();
            Log.Verbose("{AddressesHex}HAS Unequip items: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            // Update QuestList only when QuestSheet.Count is greater than QuestList.Count
            var questList  = avatarState.questList;
            var questSheet = states.GetQuestSheet();

            if (questList.Count() < questSheet.Count)
            {
                questList.UpdateList(
                    questSheet,
                    states.GetSheet <QuestRewardSheet>(),
                    states.GetSheet <QuestItemRewardSheet>(),
                    states.GetSheet <EquipmentItemRecipeSheet>());
            }

            sw.Stop();
            Log.Verbose("{AddressesHex}HAS Update QuestList: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            var simulator = new StageSimulator(
                ctx.Random,
                avatarState,
                foods,
                worldId,
                stageId,
                states.GetStageSimulatorSheets(),
                costumeStatSheet,
                StageSimulator.ConstructorVersionV100080,
                playCount);

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

            sw.Restart();
            simulator.Simulate(playCount);
            sw.Stop();
            Log.Verbose("{AddressesHex}HAS Simulator.SimulateV2(): {Elapsed}", addressesHex, sw.Elapsed);

            Log.Verbose(
                "{AddressesHex}Execute HackAndSlash({AvatarAddress}); worldId: {WorldId}, stageId: {StageId}, result: {Result}, " +
                "clearWave: {ClearWave}, totalWave: {TotalWave}",
                addressesHex,
                avatarAddress,
                worldId,
                stageId,
                simulator.Log.result,
                simulator.Log.clearedWaveNumber,
                simulator.Log.waveCount
                );

            sw.Restart();
            if (simulator.Log.IsClear)
            {
                var worldUnlockSheet = states.GetSheet <WorldUnlockSheet>();
                simulator.Player.worldInformation.ClearStage(
                    worldId,
                    stageId,
                    ctx.BlockIndex,
                    worldSheet,
                    worldUnlockSheet
                    );
            }

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

            avatarState.Update(simulator);

            var materialSheet = states.GetSheet <MaterialItemSheet>();

            avatarState.UpdateQuestRewards(materialSheet);

            avatarState.updatedAt = ctx.BlockIndex;
            avatarState.mailBox.CleanUp();
            states = states
                     .SetState(avatarAddress, avatarState.SerializeV2())
                     .SetState(inventoryAddress, avatarState.inventory.Serialize())
                     .SetState(worldInformationAddress, avatarState.worldInformation.Serialize())
                     .SetState(questListAddress, avatarState.questList.Serialize());

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

            if (simulator.Log.IsClear && states.TryGetState(rankingMapAddress, out Dictionary d))
            {
                var ranking = new RankingMapState(d);
                ranking.Update(avatarState);

                sw.Stop();
                Log.Verbose("{AddressesHex}HAS Update RankingState: {Elapsed}", addressesHex, sw.Elapsed);
                sw.Restart();

                var serialized = ranking.Serialize();

                sw.Stop();
                Log.Verbose("{AddressesHex}HAS Serialize RankingState: {Elapsed}", addressesHex, sw.Elapsed);
                sw.Restart();
                states = states.SetState(rankingMapAddress, serialized);
            }
            sw.Stop();
            Log.Verbose("{AddressesHex}HAS Set RankingState: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            TimeSpan totalElapsed = DateTimeOffset.UtcNow - started;

            Log.Verbose("{AddressesHex}HAS Total Executed Time: {Elapsed}", addressesHex, totalElapsed);
            return(states);
        }
示例#5
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IActionContext ctx    = context;
            var            states = ctx.PreviousStates;

            if (ctx.Rehearsal)
            {
                states = states.SetState(RankingState.Address, MarkChanged);
                states = states.SetState(avatarAddress, MarkChanged);
                states = states.SetState(WeeklyArenaAddress, MarkChanged);
                return(states.SetState(ctx.Signer, MarkChanged));
            }

            var sw = new Stopwatch();

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

            Log.Debug("HAS exec started.");

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

            sw.Stop();
            Log.Debug("HAS Get AgentAvatarStates: {Elapsed}", sw.Elapsed);

            sw.Restart();
            var tableSheetState = TableSheetsState.FromActionContext(ctx);

            sw.Stop();
            Log.Debug("HAS Get TableSheetsState: {Elapsed}", sw.Elapsed);

            sw.Restart();
            var tableSheets = TableSheets.FromTableSheetsState(tableSheetState);

            sw.Stop();
            Log.Debug("HAS Initialize TableSheets: {Elapsed}", sw.Elapsed);

            // worldId와 stageId가 유효한지 확인합니다.

            if (!tableSheets.WorldSheet.TryGetValue(worldId, out var worldRow))
            {
                return(LogError(
                           context,
                           "Not fount {WorldId} in TableSheets.WorldSheet.",
                           worldId
                           ));
            }

            if (stageId < worldRow.StageBegin ||
                stageId > worldRow.StageEnd)
            {
                return(LogError(
                           context,
                           "{WorldId} world is not contains {StageId} stage: {StageBegin}-{StageEnd}",
                           stageId,
                           worldRow.Id,
                           worldRow.StageBegin,
                           worldRow.StageEnd
                           ));
            }

            if (!tableSheets.StageSheet.TryGetValue(stageId, out var stageRow))
            {
                return(LogError(
                           context,
                           "Not fount stage id in TableSheets.StageSheet: {StageId}",
                           stageId
                           ));
            }

            var worldInformation = avatarState.worldInformation;

            if (!worldInformation.TryGetWorld(worldId, out var world))
            {
                // NOTE: 이 경우는 아바타 생성 시에는 WorldSheet에 없던 worldId가 새로 추가된 경우로 볼 수 있습니다.
                if (!worldInformation.TryAddWorld(worldRow, out world))
                {
                    return(LogError(context, "Failed to add {WorldId} world to WorldInformation.", worldId));
                }
            }

            if (!world.IsUnlocked)
            {
                return(LogError(context, "Aborted as the world {WorldId} is locked.", worldId));
            }

            if (world.StageBegin != worldRow.StageBegin ||
                world.StageEnd != worldRow.StageEnd)
            {
                // NOTE: 이 경우는 아바타 생성 이후에 worldId가 포함하는 stageId의 범위가 바뀐 경우로 볼 수 있습니다.
                if (!worldInformation.TryUpdateWorld(worldRow, out world))
                {
                    return(LogError(context, "Failed to update {WorldId} world in WorldInformation.", worldId));
                }

                if (world.StageBegin != worldRow.StageBegin ||
                    world.StageEnd != worldRow.StageEnd)
                {
                    return(LogError(context, "Failed to update {WorldId} world in WorldInformation.", worldId));
                }
            }

            if (world.IsStageCleared && stageId > world.StageClearedId + 1 ||
                !world.IsStageCleared && stageId != world.StageBegin)
            {
                return(LogError(
                           context,
                           "Aborted as the stage ({WorldId}/{StageId}) is not cleared; cleared stage: {StageClearedId}",
                           worldId,
                           stageId,
                           world.StageClearedId
                           ));
            }

            // 장비가 유효한지 검사한다.
            if (!avatarState.ValidateEquipments(equipments, context.BlockIndex))
            {
                // 장비가 유효하지 않은 에러.
                return(LogError(context, "Aborted as the equipment is invalid."));
            }

            sw.Restart();
            if (avatarState.actionPoint < stageRow.CostAP)
            {
                return(LogError(
                           context,
                           "Aborted due to insufficient action point: {ActionPointBalance} < {ActionCost}",
                           avatarState.actionPoint,
                           stageRow.CostAP
                           ));
            }

            avatarState.actionPoint -= stageRow.CostAP;

            avatarState.EquipCostumes(costumes);

            avatarState.EquipEquipments(equipments);
            sw.Stop();
            Log.Debug("HAS Unequip items: {Elapsed}", sw.Elapsed);

            sw.Restart();
            var simulator = new StageSimulator(
                ctx.Random,
                avatarState,
                foods,
                worldId,
                stageId,
                tableSheets
                );

            sw.Stop();
            Log.Debug("HAS Initialize Simulator: {Elapsed}", sw.Elapsed);

            sw.Restart();
            simulator.Simulate();
            sw.Stop();
            Log.Debug("HAS Simulator.Simulate(): {Elapsed}", sw.Elapsed);

            Log.Debug(
                "Execute HackAndSlash({AvatarAddress}); worldId: {WorldId}, stageId: {StageId}, result: {Result}, " +
                "clearWave: {ClearWave}, totalWave: {TotalWave}",
                avatarAddress,
                worldId,
                stageId,
                simulator.Log.result,
                simulator.Log.clearedWaveNumber,
                simulator.Log.waveCount
                );

            sw.Restart();
            if (simulator.Log.IsClear)
            {
                try
                {
                    simulator.Player.worldInformation.ClearStage(
                        worldId,
                        stageId,
                        ctx.BlockIndex,
                        tableSheets.WorldSheet,
                        tableSheets.WorldUnlockSheet
                        );
                }
                catch (FailedToUnlockWorldException e)
                {
                    Log.Error(e.Message);
                    throw;
                }
            }

            sw.Stop();
            Log.Debug("HAS ClearStage: {Elapsed}", sw.Elapsed);

            sw.Restart();
            avatarState.Update(simulator);

            avatarState.UpdateQuestRewards(ctx);

            avatarState.updatedAt = DateTimeOffset.UtcNow;
            states = states.SetState(avatarAddress, avatarState.Serialize());

            sw.Stop();
            Log.Debug("HAS Set AvatarState: {Elapsed}", sw.Elapsed);

            sw.Restart();
            if (states.TryGetState(RankingState.Address, out Dictionary d) && simulator.Log.IsClear)
            {
                var ranking = new RankingState(d);
                ranking.Update(avatarState);

                sw.Stop();
                Log.Debug("HAS Update RankingState: {Elapsed}", sw.Elapsed);
                sw.Restart();

                var serialized = ranking.Serialize();

                sw.Stop();
                Log.Debug("HAS Serialize RankingState: {Elapsed}", sw.Elapsed);
                sw.Restart();
                states = states.SetState(RankingState.Address, serialized);
            }

            sw.Stop();
            Log.Debug("HAS Set RankingState: {Elapsed}", sw.Elapsed);

            sw.Restart();
            if (states.TryGetState(WeeklyArenaAddress, out Dictionary weeklyDict))
            {
                var weekly = new WeeklyArenaState(weeklyDict);
                if (!weekly.Ended)
                {
                    if (weekly.ContainsKey(avatarAddress))
                    {
                        var info = weekly[avatarAddress];
                        info.Update(avatarState, tableSheets.CharacterSheet);
                        weekly.Update(info);
                    }
                    else
                    {
                        weekly.Set(avatarState, tableSheets.CharacterSheet);
                    }

                    sw.Stop();
                    Log.Debug("HAS Update WeeklyArenaState: {Elapsed}", sw.Elapsed);

                    sw.Restart();
                    var weeklySerialized = weekly.Serialize();
                    sw.Stop();
                    Log.Debug("HAS Serialize RankingState: {Elapsed}", sw.Elapsed);

                    states = states.SetState(weekly.address, weeklySerialized);
                }
            }

            Result = simulator.Log;

            var ended = DateTimeOffset.UtcNow;

            Log.Debug("HAS Total Executed Time: {Elapsed}", ended - started);
            return(states.SetState(ctx.Signer, agentState.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)
            {
                states = states.SetState(avatarAddress, MarkChanged);
                states = states
                         .SetState(inventoryAddress, MarkChanged)
                         .SetState(worldInformationAddress, MarkChanged)
                         .SetState(questListAddress, MarkChanged);
                return(states.SetState(ctx.Signer, MarkChanged));
            }

            var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress);

            var sw = new Stopwatch();

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

            Log.Verbose("{AddressesHex}Mimisbrunnr exec started", addressesHex);

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

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

            var worldSheet = states.GetSheet <WorldSheet>();

            if (!worldSheet.TryGetValue(worldId, out var worldRow, false))
            {
                throw new SheetRowNotFoundException(addressesHex, nameof(WorldSheet), worldId);
            }

            if (stageId < worldRow.StageBegin ||
                stageId > worldRow.StageEnd)
            {
                throw new SheetRowColumnException(
                          $"{addressesHex}{worldId} world is not contains {worldRow.Id} stage: " +
                          $"{worldRow.StageBegin}-{worldRow.StageEnd}");
            }

            var stageSheet = states.GetSheet <StageSheet>();

            if (!stageSheet.TryGetValue(stageId, out var stageRow))
            {
                throw new SheetRowNotFoundException(addressesHex, nameof(StageSheet), stageId);
            }

            var worldUnlockSheet = states.GetSheet <WorldUnlockSheet>();
            var worldInformation = avatarState.worldInformation;

            if (!worldInformation.TryGetWorld(worldId, out var world))
            {
                // NOTE: Add new World from WorldSheet
                worldInformation.AddAndUnlockMimisbrunnrWorld(worldRow, ctx.BlockIndex, worldSheet, worldUnlockSheet);
                if (!worldInformation.TryGetWorld(worldId, out world))
                {
                    // Do nothing.
                }
            }

            if (!world.IsUnlocked)
            {
                var worldUnlockSheetRow = worldUnlockSheet.OrderedList.FirstOrDefault(row => row.WorldIdToUnlock == worldId);
                if (!(worldUnlockSheetRow is null) &&
                    worldInformation.IsWorldUnlocked(worldUnlockSheetRow.WorldId) &&
                    worldInformation.IsStageCleared(worldUnlockSheetRow.StageId))
                {
                    worldInformation.UnlockWorld(worldId, ctx.BlockIndex, worldSheet);
                    if (!worldInformation.TryGetWorld(worldId, out world))
                    {
                        // Do nothing.
                    }
                }
            }

            if (!world.IsUnlocked)
            {
                throw new InvalidWorldException($"{addressesHex}{worldId} is locked.");
            }

            if (world.StageBegin != worldRow.StageBegin ||
                world.StageEnd != worldRow.StageEnd)
            {
                worldInformation.UpdateWorld(worldRow);
            }

            if (world.IsStageCleared && stageId > world.StageClearedId + 1 ||
                !world.IsStageCleared && stageId != world.StageBegin)
            {
                throw new InvalidStageException(
                          $"{addressesHex}Aborted as the stage ({worldId}/{stageId}) is not cleared; " +
                          $"cleared stage: {world.StageClearedId}"
                          );
            }

            sw.Restart();
            var mimisbrunnrSheet = states.GetSheet <MimisbrunnrSheet>();

            if (!mimisbrunnrSheet.TryGetValue(stageId, out var mimisbrunnrSheetRow))
            {
                throw new SheetRowNotFoundException("MimisbrunnrSheet", addressesHex, stageId);
            }

            foreach (var equipmentId in equipments)
            {
                if (avatarState.inventory.TryGetNonFungibleItem(equipmentId, out ItemUsable itemUsable))
                {
                    var elementalType = ((Equipment)itemUsable).ElementalType;
                    if (!mimisbrunnrSheetRow.ElementalTypes.Exists(x => x == elementalType))
                    {
                        throw new InvalidElementalException(
                                  $"{addressesHex}ElementalType of {equipmentId} does not match.");
                    }
                }
            }
            sw.Stop();
            Log.Verbose("{AddressesHex}Mimisbrunnr Check Equipments ElementalType: {Elapsed}", addressesHex, sw.Elapsed);

            avatarState.ValidateEquipmentsV2(equipments, context.BlockIndex);
            avatarState.ValidateConsumable(foods, context.BlockIndex);
            avatarState.ValidateCostume(costumes);

            sw.Restart();

            if (playCount <= 0)
            {
                throw new PlayCountIsZeroException($"{addressesHex}playCount must be greater than 0. " +
                                                   $"current playCount : {playCount}");
            }

            var totalCostActionPoint = stageRow.CostAP * playCount;

            if (avatarState.actionPoint < totalCostActionPoint)
            {
                throw new NotEnoughActionPointException(
                          $"{addressesHex}Aborted due to insufficient action point: " +
                          $"{avatarState.actionPoint} < totalAP({totalCostActionPoint}) = cost({stageRow.CostAP}) * boostCount({playCount})"
                          );
            }
            avatarState.actionPoint -= totalCostActionPoint;
            var equippableItem = new List <Guid>();

            equippableItem.AddRange(costumes);
            equippableItem.AddRange(equipments);
            avatarState.EquipItems(equippableItem);
            sw.Stop();
            Log.Verbose("{AddressesHex}Mimisbrunnr Unequip items: {Elapsed}", addressesHex, sw.Elapsed);

            sw.Restart();
            var costumeStatSheet = states.GetSheet <CostumeStatSheet>();
            var simulator        = new StageSimulator(
                ctx.Random,
                avatarState,
                foods,
                worldId,
                stageId,
                states.GetStageSimulatorSheets(),
                costumeStatSheet,
                StageSimulator.ConstructorVersionV100080,
                playCount);

            sw.Stop();
            Log.Verbose("{AddressesHex}Mimisbrunnr Initialize Simulator: {Elapsed}", addressesHex, sw.Elapsed);

            sw.Restart();
            simulator.Simulate(playCount);
            sw.Stop();
            Log.Verbose("{AddressesHex}Mimisbrunnr Simulator.Simulate(): {Elapsed}", addressesHex, sw.Elapsed);

            Log.Verbose(
                "{AddressesHex}Execute Mimisbrunnr({AvatarAddress}); worldId: {WorldId}, stageId: {StageId}, result: {Result}, " +
                "clearWave: {ClearWave}, totalWave: {TotalWave}",
                addressesHex,
                avatarAddress,
                worldId,
                stageId,
                simulator.Log.result,
                simulator.Log.clearedWaveNumber,
                simulator.Log.waveCount
                );

            sw.Restart();
            if (simulator.Log.IsClear)
            {
                simulator.Player.worldInformation.ClearStage(
                    worldId,
                    stageId,
                    ctx.BlockIndex,
                    worldSheet,
                    worldUnlockSheet
                    );
            }
            sw.Stop();
            Log.Verbose("{AddressesHex}Mimisbrunnr ClearStage: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            avatarState.Update(simulator);

            var materialSheet = states.GetSheet <MaterialItemSheet>();

            avatarState.UpdateQuestRewards(materialSheet);

            avatarState.updatedAt = ctx.BlockIndex;
            avatarState.mailBox.CleanUp();
            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}Mimisbrunnr Set AvatarState: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            var ended = DateTimeOffset.UtcNow;

            Log.Verbose("{AddressesHex}Mimisbrunnr Total Executed Time: {Elapsed}", addressesHex, ended - started);
            return(states);
        }