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