Example #1
0
        public void GetArenaInfos_By_Upper_And_Lower_Range(int infoCount, int targetRank, int upperRange, int lowerRange, int expected)
        {
            var tableState =
                TableSheets.FromTableSheetsState(TableSheetsImporter.ImportTableSheets());
            var     weeklyArenaState = new WeeklyArenaState(new PrivateKey().ToAddress());
            Address targetAddress;

            for (var i = 0; i < infoCount; i++)
            {
                var avatarAddress = new PrivateKey().ToAddress();
                if (i + 1 == targetRank)
                {
                    targetAddress = avatarAddress;
                }

                var avatarState = new AvatarState(
                    avatarAddress,
                    new PrivateKey().ToAddress(),
                    0L,
                    tableState,
                    new GameConfigState(),
                    i.ToString());
                weeklyArenaState.Add(
                    new PrivateKey().ToAddress(),
                    new ArenaInfo(avatarState, tableState.CharacterSheet, true));
            }

            var arenaInfos = weeklyArenaState.GetArenaInfos(targetAddress, upperRange, lowerRange);

            Assert.Equal(expected, arenaInfos.Count);
        }
Example #2
0
 public CombinationConsumableTest()
 {
     _agentAddress  = default;
     _avatarAddress = _agentAddress.Derive("avatar");
     _slotAddress   = _avatarAddress.Derive(
         string.Format(
             CultureInfo.InvariantCulture,
             CombinationSlotState.DeriveFormat,
             0
             )
         );
     _tableSheetsState = TableSheetsImporter.ImportTableSheets();
     _tableSheets      = TableSheets.FromTableSheetsState(_tableSheetsState);
     _random           = new ItemEnhancementTest.TestRandom();
 }
Example #3
0
        public void Execute()
        {
            var privateKey   = new PrivateKey();
            var agentAddress = privateKey.PublicKey.ToAddress();
            var agentState   = new AgentState(agentAddress);

            var tableSheets   = TableSheets.FromTableSheetsState(_tableSheetsState);
            var avatarAddress = agentAddress.Derive("avatar");
            var avatarState   = new AvatarState(
                avatarAddress,
                agentAddress,
                0,
                tableSheets,
                new GameConfigState()
                );

            agentState.avatarAddresses.Add(0, avatarAddress);

            var row        = tableSheets.EquipmentItemSheet.Values.First();
            var equipment  = (Equipment)ItemFactory.CreateItemUsable(row, default, 0, 0);
Example #4
0
        public void GetArenaInfos_By_FirstRank_And_Count_Throw(int infoCount, int firstRank)
        {
            var tableState =
                TableSheets.FromTableSheetsState(TableSheetsImporter.ImportTableSheets());
            var weeklyArenaState = new WeeklyArenaState(new PrivateKey().ToAddress());

            for (var i = 0; i < infoCount; i++)
            {
                var avatarState = new AvatarState(
                    new PrivateKey().ToAddress(),
                    new PrivateKey().ToAddress(),
                    0L,
                    tableState,
                    new GameConfigState(),
                    i.ToString());
                weeklyArenaState.Add(
                    new PrivateKey().ToAddress(),
                    new ArenaInfo(avatarState, tableState.CharacterSheet, true));
            }

            Assert.Throws <ArgumentOutOfRangeException>(() =>
                                                        weeklyArenaState.GetArenaInfos(firstRank, 100));
        }
Example #5
0
        public void GetArenaInfos_By_FirstRank_And_Count(int infoCount, int firstRank, int count, int expected)
        {
            var tableState =
                TableSheets.FromTableSheetsState(TableSheetsImporter.ImportTableSheets());
            var weeklyArenaState = new WeeklyArenaState(new PrivateKey().ToAddress());

            for (var i = 0; i < infoCount; i++)
            {
                var avatarState = new AvatarState(
                    new PrivateKey().ToAddress(),
                    new PrivateKey().ToAddress(),
                    0L,
                    tableState,
                    new GameConfigState(),
                    i.ToString());
                weeklyArenaState.Add(
                    new PrivateKey().ToAddress(),
                    new ArenaInfo(avatarState, tableState.CharacterSheet, true));
            }

            var arenaInfos = weeklyArenaState.GetArenaInfos(firstRank, count);

            Assert.Equal(expected, arenaInfos.Count);
        }
Example #6
0
 public StageSimulatorTest()
 {
     _tableSheets = TableSheets.FromTableSheetsState(TableSheetsImporter.ImportTableSheets());
     _random      = new ItemEnhancementTest.TestRandom();
     _avatarState = new AvatarState(default, default, 0, _tableSheets, new GameConfigState());
Example #7
0
 public RedeemCodeTest()
 {
     _tableSheetsState = TableSheetsImporter.ImportTableSheets();
     _tableSheets      = TableSheets.FromTableSheetsState(_tableSheetsState);
 }
Example #8
0
 public SimulatorTest()
 {
     _tableSheets = TableSheets.FromTableSheetsState(TableSheetsImporter.ImportTableSheets());
     _random      = new ItemEnhancementTest.TestRandom();
 }
Example #9
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()));
        }
Example #10
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);
        }
Example #11
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()));
        }