예제 #1
0
        public RankingBattle4Test()
        {
            _initialState = new State();

            var sheets = TableSheetsImporter.ImportSheets();

            foreach (var(key, value) in sheets)
            {
                _initialState = _initialState.SetState(
                    Addresses.TableSheet.Derive(key),
                    value.Serialize());
            }

            _tableSheets = new TableSheets(sheets);

            var rankingMapAddress = new PrivateKey().ToAddress();

            var(agent1State, avatar1State) = GetAgentStateWithAvatarState(
                sheets,
                _tableSheets,
                rankingMapAddress);
            _agent1Address  = agent1State.address;
            _avatar1Address = avatar1State.address;

            var(agent2State, avatar2State) = GetAgentStateWithAvatarState(
                sheets,
                _tableSheets,
                rankingMapAddress);
            var agent2Address = agent2State.address;

            _avatar2Address = avatar2State.address;

            var weeklyArenaState = new WeeklyArenaState(0);

            weeklyArenaState.Set(avatar1State, _tableSheets.CharacterSheet);
            weeklyArenaState[_avatar1Address].Activate();
            weeklyArenaState.Set(avatar2State, _tableSheets.CharacterSheet);
            weeklyArenaState[_avatar2Address].Activate();
            _weeklyArenaAddress = weeklyArenaState.address;

            _initialState = _initialState
                            .SetState(_agent1Address, agent1State.Serialize())
                            .SetState(_avatar1Address, avatar1State.Serialize())
                            .SetState(agent2Address, agent2State.Serialize())
                            .SetState(_avatar2Address, avatar2State.Serialize())
                            .SetState(_weeklyArenaAddress, weeklyArenaState.Serialize());
        }
예제 #2
0
        public void GetAgentAddresses()
        {
            var privateKey   = new PrivateKey();
            var agentAddress = privateKey.PublicKey.ToAddress();

            var avatarAddress = agentAddress.Derive("avatar");
            var avatarState   = new AvatarState(avatarAddress, agentAddress, 0, _tableSheets, new GameConfigState());

            var avatarAddress2 = agentAddress.Derive("avatar2");
            var avatarState2   = new AvatarState(avatarAddress2, agentAddress, 0, _tableSheets, new GameConfigState());

            var state = new WeeklyArenaState(0);

            state.Set(avatarState, _tableSheets.CharacterSheet);
            state[avatarAddress].Activate();
            state.Set(avatarState2, _tableSheets.CharacterSheet);
            state[avatarAddress2].Activate();

            Assert.Single(state.GetAgentAddresses(2));
        }
예제 #3
0
        public void Execute()
        {
            var privateKey   = new PrivateKey();
            var agentAddress = privateKey.PublicKey.ToAddress();
            var agent        = new AgentState(agentAddress);

            var avatarAddress = agentAddress.Derive("avatar");
            var avatar        = new AvatarState(avatarAddress, agentAddress, 0, _tableSheets, new GameConfigState());

            agent.avatarAddresses.Add(0, avatarAddress);

            var weekly = new WeeklyArenaState(default(Address));

            weekly.Set(avatar, _tableSheets.CharacterSheet);
            weekly.End();

            var gold = new GoldCurrencyState(new Currency("NCG", minter: null));

            var state = new State(ImmutableDictionary <Address, IValue> .Empty
                                  .Add(default, weekly.Serialize())
예제 #4
0
        public void WeeklyArenaRankingBoard(bool resetCount, bool updateNext)
        {
            var weekly = new WeeklyArenaState(0);

            weekly.Set(_avatarState, _tableSheets.CharacterSheet);
            weekly[_avatarState.address].Update(weekly[_avatarState.address], BattleLog.Result.Lose);
            var gameConfigState = new GameConfigState();

            gameConfigState.Set(_tableSheets.GameConfigSheet);
            var state = _baseState
                        .SetState(weekly.address, weekly.Serialize())
                        .SetState(gameConfigState.address, gameConfigState.Serialize());
            var blockIndex = 0;

            if (resetCount)
            {
                blockIndex = gameConfigState.DailyArenaInterval;
            }

            if (updateNext)
            {
                weekly[_avatarState.address].Activate();
                blockIndex = gameConfigState.WeeklyArenaInterval;
                // Avoid NRE in test case.
                var nextWeekly = new WeeklyArenaState(1);
                state = state
                        .SetState(weekly.address, weekly.Serialize())
                        .SetState(nextWeekly.address, nextWeekly.Serialize());
            }

            Assert.False(weekly.Ended);
            Assert.Equal(4, weekly[_avatarState.address].DailyChallengeCount);

            var action = new RewardGold();

            var ctx = new ActionContext()
            {
                BlockIndex     = blockIndex,
                PreviousStates = _baseState,
                Miner          = default,
예제 #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;

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

            Log.Warning($"{nameof(HackAndSlash)} is deprecated. Please use ${nameof(HackAndSlash2)}");
            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))
            {
                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);

            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()
                );

            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);
                        weekly.Update(info);
                    }
                    else
                    {
                        weekly.Set(avatarState, 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()));
        }
예제 #7
0
        public void Execute()
        {
            var tableSheets  = TableSheets.FromTableSheetsState(_tableSheetsState);
            var itemId       = tableSheets.WeeklyArenaRewardSheet.Values.First().Reward.ItemId;
            var privateKey   = new PrivateKey();
            var agentAddress = privateKey.PublicKey.ToAddress();
            var agent        = new AgentState(agentAddress);

            var avatarAddress = agentAddress.Derive("avatar");
            var avatarState   = new AvatarState(avatarAddress, agentAddress, 0, tableSheets, new GameConfigState())
            {
                level = 10,
            };

            avatarState.worldInformation.ClearStage(
                1,
                GameConfig.RequireClearedStageLevel.ActionsInRankingBoard,
                1,
                tableSheets.WorldSheet,
                tableSheets.WorldUnlockSheet
                );
            agent.avatarAddresses.Add(0, avatarAddress);

            Assert.False(avatarState.inventory.HasItem(itemId));

            var avatarAddress2 = agentAddress.Derive("avatar2");
            var avatarState2   = new AvatarState(avatarAddress2, agentAddress, 0, tableSheets, new GameConfigState());

            avatarState2.worldInformation.ClearStage(
                1,
                GameConfig.RequireClearedStageLevel.ActionsInRankingBoard,
                1,
                tableSheets.WorldSheet,
                tableSheets.WorldUnlockSheet
                );
            agent.avatarAddresses.Add(1, avatarAddress);

            var weekly = new WeeklyArenaState(0);

            weekly.Set(avatarState, tableSheets.CharacterSheet);
            weekly[avatarAddress].Activate();
            weekly.Set(avatarState2, tableSheets.CharacterSheet);
            weekly[avatarAddress2].Activate();

            var state = new State(ImmutableDictionary <Address, IValue> .Empty
                                  .Add(_tableSheetsState.address, _tableSheetsState.Serialize())
                                  .Add(weekly.address, weekly.Serialize())
                                  .Add(agentAddress, agent.Serialize())
                                  .Add(avatarAddress, avatarState.Serialize())
                                  .Add(avatarAddress2, avatarState2.Serialize()));

            var action = new RankingBattle
            {
                AvatarAddress      = avatarAddress,
                EnemyAddress       = avatarAddress2,
                WeeklyArenaAddress = weekly.address,
                costumeIds         = new List <int>(),
                equipmentIds       = new List <Guid>(),
                consumableIds      = new List <Guid>(),
            };

            Assert.Null(action.Result);

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

            var newState = nextState.GetAvatarState(avatarAddress);

            var newWeeklyState = nextState.GetWeeklyArenaState(0);

            Assert.True(newState.inventory.HasItem(itemId));
            Assert.NotNull(action.Result);
            Assert.Contains(typeof(GetReward), action.Result.Select(e => e.GetType()));
            Assert.Equal(BattleLog.Result.Win, action.Result.result);
            Assert.True(newWeeklyState[avatarAddress].Score > weekly[avatarAddress].Score);
        }