示例#1
0
        public void Serialize()
        {
            var state         = new RankingState();
            var avatarAddress = new PrivateKey().ToAddress();

            state.UpdateRankingMap(avatarAddress);
            var serialized = state.Serialize();

            var des = new RankingState((Dictionary)serialized);

            Assert.Equal(Addresses.Ranking, des.address);
            Assert.Contains(des.RankingMap, m => m.Value.Contains(avatarAddress));
        }
示例#2
0
        public void Execute()
        {
            var action = new CreateAvatar()
            {
                avatarAddress = _avatarAddress,
                index         = 0,
                hair          = 0,
                ear           = 0,
                lens          = 0,
                tail          = 0,
                name          = "test",
            };

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

            for (var i = 0; i < RankingState.RankingMapCapacity; i++)
            {
                ranking.RankingMap[RankingState.Derive(i)] = new HashSet <Address>().ToImmutableHashSet();
            }

            var sheets = TableSheetsImporter.ImportSheets();
            var state  = new State()
                         .SetState(GoldCurrencyState.Address, gold.Serialize())
                         .SetState(
                Addresses.GoldDistribution,
                GoldDistributionTest.Fixture.Select(v => v.Serialize()).Serialize()
                )
                         .SetState(
                Addresses.GameConfig,
                new GameConfigState(sheets[nameof(GameConfigSheet)]).Serialize()
                )
                         .SetState(Addresses.Ranking, ranking.Serialize())
                         .MintAsset(GoldCurrencyState.Address, gold.Currency * 100000000000);

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

            var nextState = action.Execute(new ActionContext()
            {
                PreviousStates = state,
                Signer         = _agentAddress,
                BlockIndex     = 0,
            });

            Assert.Equal(
                0,
                nextState.GetBalance(default, gold.Currency).MajorUnit
示例#3
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IActionContext ctx              = context;
            var            states           = ctx.PreviousStates;
            var            weeklyArenaState = new WeeklyArenaState(0);

            if (ctx.Rehearsal)
            {
                states = states.SetState(RankingState.Address, MarkChanged);
                states = states.SetState(ShopState.Address, MarkChanged);
                states = states.SetState(TableSheetsState.Address, MarkChanged);
                states = states.SetState(weeklyArenaState.address, MarkChanged);
                states = states.SetState(GameConfigState.Address, MarkChanged);
                states = states.SetState(RedeemCodeState.Address, MarkChanged);
                states = states.SetState(AdminState.Address, MarkChanged);
                states = states.SetState(ActivatedAccountsState.Address, MarkChanged);
                states = states.SetState(GoldCurrencyState.Address, MarkChanged);
                states = states.SetState(Addresses.GoldDistribution, MarkChanged);
                return(states);
            }

            if (ctx.BlockIndex != 0)
            {
                return(states);
            }

            states = states
                     .SetState(weeklyArenaState.address, weeklyArenaState.Serialize())
                     .SetState(RankingState.Address, RankingState.Serialize())
                     .SetState(ShopState.Address, ShopState.Serialize())
                     .SetState(TableSheetsState.Address, TableSheetsState.Serialize())
                     .SetState(GameConfigState.Address, GameConfigState.Serialize())
                     .SetState(RedeemCodeState.Address, RedeemCodeState.Serialize())
                     .SetState(AdminState.Address, AdminAddressState.Serialize())
                     .SetState(ActivatedAccountsState.Address, ActivatedAccountsState.Serialize())
                     .SetState(GoldCurrencyState.Address, GoldCurrencyState.Serialize())
                     .SetState(Addresses.GoldDistribution, GoldDistributions.Select(v => v.Serialize()).Serialize());

            states = states.MintAsset(GoldCurrencyState.Address, GoldCurrencyState.Currency, 1000000000);
            return(states);
        }
示例#4
0
        public void Deterministic_Between_SerializeV1_And_SerializeV1_With_Deterministic_Problem()
        {
            var state = new RankingState();

            for (var i = 0; i < 1000; i++)
            {
                state.UpdateRankingMap(new PrivateKey().ToAddress());
            }

            var serializedV1 = state.Serialize();
            var serializedV1WithDeterministicProblem = SerializeV1_With_Deterministic_Problem(state);

            Assert.Equal(serializedV1WithDeterministicProblem, serializedV1);

            var deserialized   = new RankingState((Bencodex.Types.Dictionary)serializedV1);
            var deserializedV1 = new RankingState((Bencodex.Types.Dictionary)serializedV1WithDeterministicProblem);

            serializedV1 = deserialized.Serialize();
            serializedV1WithDeterministicProblem = deserializedV1.Serialize();
            Assert.Equal(serializedV1WithDeterministicProblem, serializedV1);
        }
示例#5
0
        public InitializeStates(
            RankingState rankingState,
            ShopState shopState,
            Dictionary <string, string> tableSheets,
            GameConfigState gameConfigState,
            RedeemCodeState redeemCodeState,
            AdminState adminAddressState,
            ActivatedAccountsState activatedAccountsState,
            GoldCurrencyState goldCurrencyState,
            GoldDistribution[] goldDistributions,
            PendingActivationState[] pendingActivationStates,
            AuthorizedMinersState authorizedMinersState = null,
            CreditsState creditsState = null)
        {
            Ranking           = (Bencodex.Types.Dictionary)rankingState.Serialize();
            Shop              = (Bencodex.Types.Dictionary)shopState.Serialize();
            TableSheets       = tableSheets;
            GameConfig        = (Bencodex.Types.Dictionary)gameConfigState.Serialize();
            RedeemCode        = (Bencodex.Types.Dictionary)redeemCodeState.Serialize();
            AdminAddress      = (Bencodex.Types.Dictionary)adminAddressState.Serialize();
            ActivatedAccounts = (Bencodex.Types.Dictionary)activatedAccountsState.Serialize();
            GoldCurrency      = (Bencodex.Types.Dictionary)goldCurrencyState.Serialize();
            GoldDistributions = new Bencodex.Types.List(
                goldDistributions.Select(d => d.Serialize()).Cast <Bencodex.Types.IValue>()
                );
            PendingActivations = new Bencodex.Types.List(pendingActivationStates.Select(p => p.Serialize()));

            if (!(authorizedMinersState is null))
            {
                AuthorizedMiners = (Bencodex.Types.Dictionary)authorizedMinersState.Serialize();
            }

            if (!(creditsState is null))
            {
                Credits = (Bencodex.Types.Dictionary)creditsState.Serialize();
            }
        }
示例#6
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()));
        }
示例#7
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IActionContext ctx           = context;
            var            states        = ctx.PreviousStates;
            var            avatarAddress = ctx.Signer.Derive(
                string.Format(
                    CultureInfo.InvariantCulture,
                    DeriveFormat,
                    index
                    )
                );
            var inventoryAddress        = avatarAddress.Derive(LegacyInventoryKey);
            var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey);
            var questListAddress        = avatarAddress.Derive(LegacyQuestListKey);

            if (ctx.Rehearsal)
            {
                states = states.SetState(ctx.Signer, MarkChanged);
                for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++)
                {
                    var slotAddress = avatarAddress.Derive(
                        string.Format(
                            CultureInfo.InvariantCulture,
                            CombinationSlotState.DeriveFormat,
                            i
                            )
                        );
                    states = states.SetState(slotAddress, MarkChanged);
                }

                return(states
                       .SetState(avatarAddress, MarkChanged)
                       .SetState(Addresses.Ranking, MarkChanged)
                       .SetState(inventoryAddress, MarkChanged)
                       .SetState(worldInformationAddress, MarkChanged)
                       .SetState(questListAddress, MarkChanged)
                       .MarkBalanceChanged(GoldCurrencyMock, GoldCurrencyState.Address, context.Signer));
            }

            var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress);

            if (!Regex.IsMatch(name, GameConfig.AvatarNickNamePattern))
            {
                throw new InvalidNamePatternException(
                          $"{addressesHex}Aborted as the input name {name} does not follow the allowed name pattern.");
            }

            var sw = new Stopwatch();

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

            Log.Verbose("{AddressesHex}CreateAvatar exec started", addressesHex);
            AgentState existingAgentState = states.GetAgentState(ctx.Signer);
            var        agentState         = existingAgentState ?? new AgentState(ctx.Signer);
            var        avatarState        = states.GetAvatarState(avatarAddress);

            if (!(avatarState is null))
            {
                throw new InvalidAddressException(
                          $"{addressesHex}Aborted as there is already an avatar at {avatarAddress}.");
            }

            if (!(0 <= index && index < GameConfig.SlotCount))
            {
                throw new AvatarIndexOutOfRangeException(
                          $"{addressesHex}Aborted as the index is out of range #{index}.");
            }

            if (agentState.avatarAddresses.ContainsKey(index))
            {
                throw new AvatarIndexAlreadyUsedException(
                          $"{addressesHex}Aborted as the signer already has an avatar at index #{index}.");
            }
            sw.Stop();
            Log.Verbose("{AddressesHex}CreateAvatar Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed);
            sw.Restart();

            Log.Verbose("{AddressesHex}Execute CreateAvatar; player: {AvatarAddress}", addressesHex, avatarAddress);

            agentState.avatarAddresses.Add(index, avatarAddress);

            // Avoid NullReferenceException in test
            var materialItemSheet = ctx.PreviousStates.GetSheet <MaterialItemSheet>();

            RankingState rankingState = ctx.PreviousStates.GetRankingState();

            var rankingMapAddress = rankingState.UpdateRankingMap(avatarAddress);

            avatarState = CreateAvatar0.CreateAvatarState(name, avatarAddress, ctx, materialItemSheet, rankingMapAddress);

            if (hair < 0)
            {
                hair = 0;
            }
            if (lens < 0)
            {
                lens = 0;
            }
            if (ear < 0)
            {
                ear = 0;
            }
            if (tail < 0)
            {
                tail = 0;
            }

            avatarState.Customize(hair, lens, ear, tail);

            foreach (var address in avatarState.combinationSlotAddresses)
            {
                var slotState =
                    new CombinationSlotState(address, GameConfig.RequireClearedStageLevel.CombinationEquipmentAction);
                states = states.SetState(address, slotState.Serialize());
            }

            avatarState.UpdateQuestRewards(materialItemSheet);

            sw.Stop();
            Log.Verbose("{AddressesHex}CreateAvatar CreateAvatarState: {Elapsed}", addressesHex, sw.Elapsed);
            var ended = DateTimeOffset.UtcNow;

            Log.Verbose("{AddressesHex}CreateAvatar Total Executed Time: {Elapsed}", addressesHex, ended - started);
            return(states
                   .SetState(ctx.Signer, agentState.Serialize())
                   .SetState(Addresses.Ranking, rankingState.Serialize())
                   .SetState(inventoryAddress, avatarState.inventory.Serialize())
                   .SetState(worldInformationAddress, avatarState.worldInformation.Serialize())
                   .SetState(questListAddress, avatarState.questList.Serialize())
                   .SetState(avatarAddress, avatarState.SerializeV2()));
        }
示例#8
0
        public static MakeInitialStateResult MakeInitialState()
        {
            var goldCurrencyState = new GoldCurrencyState(new Currency("NCG", 2, minter: null));
            var ranking           = new RankingState();

            for (var i = 0; i < RankingState.RankingMapCapacity; i++)
            {
                ranking.RankingMap[RankingState.Derive(i)] = new HashSet <Address>().ToImmutableHashSet();
            }

            var sheets       = TableSheetsImporter.ImportSheets();
            var initialState = new Tests.Action.State()
                               .SetState(GoldCurrencyState.Address, goldCurrencyState.Serialize())
                               .SetState(
                Addresses.GoldDistribution,
                GoldDistributionTest.Fixture.Select(v => v.Serialize()).Serialize()
                )
                               .SetState(
                Addresses.GameConfig,
                new GameConfigState(sheets[nameof(GameConfigSheet)]).Serialize()
                )
                               .SetState(Addresses.Ranking, ranking.Serialize());

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

            var tableSheets       = new TableSheets(sheets);
            var rankingMapAddress = new PrivateKey().ToAddress();

            var agentAddress = new PrivateKey().ToAddress();
            var agentState   = new AgentState(agentAddress);

            var avatarAddress = new PrivateKey().ToAddress();
            var avatarState   = new AvatarState(
                avatarAddress,
                agentAddress,
                0,
                tableSheets.GetAvatarSheets(),
                new GameConfigState(),
                rankingMapAddress)
            {
                worldInformation = new WorldInformation(
                    0,
                    tableSheets.WorldSheet,
                    GameConfig.RequireClearedStageLevel.ActionsInShop),
            };

            agentState.avatarAddresses[0] = avatarAddress;

            var initCurrencyGold   = goldCurrencyState.Currency * 100000000000;
            var agentCurrencyGold  = goldCurrencyState.Currency * 1000;
            var remainCurrencyGold = initCurrencyGold - agentCurrencyGold;

            initialState = initialState
                           .SetState(GoldCurrencyState.Address, goldCurrencyState.Serialize())
                           .SetState(agentAddress, agentState.Serialize())
                           .SetState(avatarAddress, avatarState.Serialize())
                           .SetState(Addresses.Shop, new ShopState().Serialize())
                           .MintAsset(GoldCurrencyState.Address, initCurrencyGold)
                           .TransferAsset(Addresses.GoldCurrency, agentAddress, agentCurrencyGold);

            var action    = new CreateTestbed();
            var nextState = action.Execute(new ActionContext()
            {
                BlockIndex     = 0,
                PreviousStates = initialState,
                Random         = new TestRandom(),
                Rehearsal      = false,
            });

            return(new MakeInitialStateResult(
                       nextState,
                       action,
                       agentState,
                       avatarState,
                       goldCurrencyState,
                       rankingMapAddress,
                       tableSheets,
                       remainCurrencyGold,
                       agentCurrencyGold));
        }