public void GetRankingInfos() { var state = new RankingMapState(_rankingMapAddress); for (var i = 0; i < 10; i++) { var avatarState = new AvatarState( _agentAddress.Derive(i.ToString()), _agentAddress, 0, _tableSheets.GetAvatarSheets(), new GameConfigState(), _rankingMapAddress, "test" ) { exp = 10 - i, }; state.Update(avatarState); } var list = state.GetRankingInfos(null); for (var index = 0; index < list.Count; index++) { var info = list[index]; Assert.Equal(10 - index, info.Exp); Assert.Equal(_agentAddress.Derive(index.ToString()), info.AvatarAddress); } }
public void Update() { var avatarAddress = _agentAddress.Derive("avatar"); var rankingMapAddress = avatarAddress.Derive("ranking_map"); var avatarState = new AvatarState( avatarAddress, _agentAddress, 0, _tableSheets.GetAvatarSheets(), new GameConfigState(), rankingMapAddress, "test" ); var state = new RankingMapState(rankingMapAddress); state.Update(avatarState); Assert.Single(state.GetRankingInfos(null)); Assert.Equal(0, state.GetRankingInfos(null).First().Exp); avatarState.exp += 100; state.Update(avatarState); Assert.Single(state.GetRankingInfos(null)); Assert.Equal(100, state.GetRankingInfos(null).First().Exp); }
/// <summary> /// 랭킹 상태를 할당한다. /// </summary> /// <param name="state"></param> public void SetRankingMapStates(RankingMapState state) { if (state is null) { Debug.LogWarning($"[{nameof(States)}.{nameof(SetRankingMapStates)}] {nameof(state)} is null."); return; } RankingMapStates[state.address] = state; RankingMapStatesSubject.OnNext(RankingMapStates); }
public async Task Query(RankingMapState rankingMapState, object expected) { const string query = @" { address capacity rankingInfos { agentAddress avatarAddress } }"; var queryResult = await ExecuteQueryAsync <RankingMapStateType>(query, source : rankingMapState); Assert.Equal(expected, queryResult.Data); }
public void Serialize() { var avatarAddress = _agentAddress.Derive("avatar"); var avatarState = new AvatarState( avatarAddress, _agentAddress, 0, _tableSheets.GetAvatarSheets(), new GameConfigState(), _rankingMapAddress, "test" ); var state = new RankingMapState(_rankingMapAddress); state.Update(avatarState); var serialized = state.Serialize(); var des = new RankingMapState((Dictionary)serialized); Assert.Equal(state.GetRankingInfos(null), des.GetRankingInfos(null)); }
public void SerializeEquals() { var avatarAddress = _agentAddress.Derive("avatar"); var avatarState = new AvatarState( avatarAddress, _agentAddress, 0, _tableSheets.GetAvatarSheets(), new GameConfigState(), _rankingMapAddress, "test" ); var avatarAddress2 = _agentAddress.Derive("avatar2"); var avatarState2 = new AvatarState( avatarAddress2, _agentAddress, 0, _tableSheets.GetAvatarSheets(), new GameConfigState(), _rankingMapAddress, "test2" ); var state = new RankingMapState(_rankingMapAddress); state.Update(avatarState); state.Update(avatarState2); var state2 = new RankingMapState(_rankingMapAddress); state2.Update(avatarState2); state2.Update(avatarState); Assert.Equal(state2.Serialize(), state.Serialize()); }
public override IAccountStateDelta Execute(IActionContext context) { IActionContext ctx = context; var states = ctx.PreviousStates; if (ctx.Rehearsal) { states = states.SetState(RankingMapAddress, MarkChanged); states = states.SetState(avatarAddress, MarkChanged); states = states.SetState(WeeklyArenaAddress, MarkChanged); return(states.SetState(ctx.Signer, MarkChanged)); } var sw = new Stopwatch(); sw.Start(); var started = DateTimeOffset.UtcNow; Log.Debug("HAS exec started."); if (!states.TryGetAvatarState(ctx.Signer, avatarAddress, out AvatarState avatarState)) { throw new FailedLoadStateException("Aborted as the avatar state of the signer was failed to load."); } sw.Stop(); Log.Debug("HAS Get AgentAvatarStates: {Elapsed}", sw.Elapsed); sw.Restart(); if (avatarState.RankingMapAddress != RankingMapAddress) { throw new InvalidAddressException("Invalid ranking map address"); } // worldId와 stageId가 유효한지 확인합니다. var worldSheet = states.GetSheet <WorldSheet>(); if (!worldSheet.TryGetValue(worldId, out var worldRow, false)) { throw new SheetRowNotFoundException(nameof(WorldSheet), worldId); } if (stageId < worldRow.StageBegin || stageId > worldRow.StageEnd) { throw new SheetRowColumnException( $"{worldId} world is not contains {worldRow.Id} stage: " + $"{worldRow.StageBegin}-{worldRow.StageEnd}"); } var stageSheet = states.GetSheet <StageSheet>(); if (!stageSheet.TryGetValue(stageId, out var stageRow)) { throw new SheetRowNotFoundException(nameof(StageSheet), stageId); } var worldInformation = avatarState.worldInformation; if (!worldInformation.TryGetWorld(worldId, out var world)) { // NOTE: Add new World from WorldSheet worldInformation.AddAndUnlockNewWorld(worldRow, ctx.BlockIndex, worldSheet); } if (!world.IsUnlocked) { throw new InvalidWorldException($"{worldId} is locked."); } if (world.StageBegin != worldRow.StageBegin || world.StageEnd != worldRow.StageEnd) { worldInformation.UpdateWorld(worldRow); } if (world.IsStageCleared && stageId > world.StageClearedId + 1 || !world.IsStageCleared && stageId != world.StageBegin) { throw new InvalidStageException( $"Aborted as the stage ({worldId}/{stageId}) is not cleared; " + $"cleared stage: {world.StageClearedId}" ); } avatarState.ValidateEquipments(equipments, context.BlockIndex); avatarState.ValidateConsumable(foods, context.BlockIndex); avatarState.ValidateCostume(new HashSet <int>(costumes)); var costumeStatSheet = states.GetSheet <CostumeStatSheet>(); sw.Restart(); if (avatarState.actionPoint < stageRow.CostAP) { throw new NotEnoughActionPointException( $"Aborted due to insufficient action point: " + $"{avatarState.actionPoint} < {stageRow.CostAP}" ); } avatarState.actionPoint -= stageRow.CostAP; avatarState.EquipCostumes(new HashSet <int>(costumes)); avatarState.EquipEquipments(equipments); sw.Stop(); Log.Debug("HAS Unequip items: {Elapsed}", sw.Elapsed); sw.Restart(); var characterSheet = states.GetSheet <CharacterSheet>(); var simulator = new StageSimulator( ctx.Random, avatarState, foods, worldId, stageId, states.GetStageSimulatorSheets(), costumeStatSheet ); sw.Stop(); Log.Debug("HAS Initialize Simulator: {Elapsed}", sw.Elapsed); sw.Restart(); simulator.Simulate(); sw.Stop(); Log.Debug("HAS Simulator.Simulate(): {Elapsed}", sw.Elapsed); Log.Debug( "Execute HackAndSlash({AvatarAddress}); worldId: {WorldId}, stageId: {StageId}, result: {Result}, " + "clearWave: {ClearWave}, totalWave: {TotalWave}", avatarAddress, worldId, stageId, simulator.Log.result, simulator.Log.clearedWaveNumber, simulator.Log.waveCount ); sw.Restart(); if (simulator.Log.IsClear) { var worldUnlockSheet = states.GetSheet <WorldUnlockSheet>(); simulator.Player.worldInformation.ClearStage( worldId, stageId, ctx.BlockIndex, worldSheet, worldUnlockSheet ); } sw.Stop(); Log.Debug("HAS ClearStage: {Elapsed}", sw.Elapsed); sw.Restart(); avatarState.Update(simulator); var materialSheet = states.GetSheet <MaterialItemSheet>(); avatarState.UpdateQuestRewards(materialSheet); avatarState.updatedAt = ctx.BlockIndex; states = states.SetState(avatarAddress, avatarState.Serialize()); sw.Stop(); Log.Debug("HAS Set AvatarState: {Elapsed}", sw.Elapsed); sw.Restart(); if (states.TryGetState(RankingMapAddress, out Dictionary d) && simulator.Log.IsClear) { var ranking = new RankingMapState(d); ranking.Update(avatarState); sw.Stop(); Log.Debug("HAS Update RankingState: {Elapsed}", sw.Elapsed); sw.Restart(); var serialized = ranking.Serialize(); sw.Stop(); Log.Debug("HAS Serialize RankingState: {Elapsed}", sw.Elapsed); sw.Restart(); states = states.SetState(RankingMapAddress, serialized); } sw.Stop(); Log.Debug("HAS Set RankingState: {Elapsed}", sw.Elapsed); sw.Restart(); if (simulator.Log.stageId >= GameConfig.RequireClearedStageLevel.ActionsInRankingBoard && simulator.Log.IsClear && states.TryGetState(WeeklyArenaAddress, out Dictionary weeklyDict)) { var weekly = new WeeklyArenaState(weeklyDict); if (!weekly.Ended) { if (weekly.ContainsKey(avatarAddress)) { var info = weekly[avatarAddress]; info.Update(avatarState, characterSheet, costumeStatSheet); weekly.Update(info); } else { weekly.SetV2(avatarState, characterSheet, costumeStatSheet); } sw.Stop(); Log.Debug("HAS Update WeeklyArenaState: {Elapsed}", sw.Elapsed); sw.Restart(); var weeklySerialized = weekly.Serialize(); sw.Stop(); Log.Debug("HAS Serialize RankingState: {Elapsed}", sw.Elapsed); states = states.SetState(weekly.address, weeklySerialized); } } Result = simulator.Log; var ended = DateTimeOffset.UtcNow; Log.Debug("HAS Total Executed Time: {Elapsed}", ended - started); return(states); }
public override IAccountStateDelta Execute(IActionContext context) { IActionContext ctx = context; var states = ctx.PreviousStates; if (ctx.Rehearsal) { states = states.SetState(RankingMapAddress, MarkChanged); states = states.SetState(avatarAddress, MarkChanged); return(states.SetState(WeeklyArenaAddress, MarkChanged)); } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var sw = new Stopwatch(); sw.Start(); var started = DateTimeOffset.UtcNow; Log.Verbose("{AddressesHex}Mimisbrunnr exec started", addressesHex); if (!states.TryGetAvatarState(ctx.Signer, avatarAddress, out AvatarState avatarState)) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load."); } sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (avatarState.RankingMapAddress != RankingMapAddress) { throw new InvalidAddressException($"{addressesHex}Invalid ranking map address"); } var worldSheet = states.GetSheet <WorldSheet>(); var worldUnlockSheet = states.GetSheet <WorldUnlockSheet>(); if (!worldSheet.TryGetValue(worldId, out var worldRow, false)) { throw new SheetRowNotFoundException(nameof(WorldSheet), worldId); } if (stageId < worldRow.StageBegin || stageId > worldRow.StageEnd) { throw new SheetRowColumnException( $"{addressesHex}{worldId} world is not contains {worldRow.Id} stage: " + $"{worldRow.StageBegin}-{worldRow.StageEnd}"); } var stageSheet = states.GetSheet <StageSheet>(); if (!stageSheet.TryGetValue(stageId, out var stageRow)) { throw new SheetRowNotFoundException(addressesHex, nameof(StageSheet), stageId); } var worldInformation = avatarState.worldInformation; if (!worldInformation.TryGetWorld(worldId, out var world)) { // NOTE: Add new World from WorldSheet worldInformation.AddAndUnlockMimisbrunnrWorld(worldRow, ctx.BlockIndex, worldSheet, worldUnlockSheet); if (!worldInformation.TryGetWorld(worldId, out world)) { // Do nothing. } } if (!world.IsUnlocked) { var worldUnlockSheetRow = worldUnlockSheet.OrderedList.FirstOrDefault(row => row.WorldIdToUnlock == worldId); if (!(worldUnlockSheetRow is null) && worldInformation.IsWorldUnlocked(worldUnlockSheetRow.WorldId) && worldInformation.IsStageCleared(worldUnlockSheetRow.StageId)) { worldInformation.UnlockWorld(worldId, ctx.BlockIndex, worldSheet); if (!worldInformation.TryGetWorld(worldId, out world)) { // Do nothing. } } } if (!world.IsUnlocked) { throw new InvalidWorldException($"{addressesHex}{worldId} is locked."); } if (world.StageBegin != worldRow.StageBegin || world.StageEnd != worldRow.StageEnd) { worldInformation.UpdateWorld(worldRow); } if (world.IsStageCleared && stageId > world.StageClearedId + 1 || !world.IsStageCleared && stageId != world.StageBegin) { throw new InvalidStageException( $"{addressesHex}Aborted as the stage ({worldId}/{stageId}) is not cleared; " + $"cleared stage: {world.StageClearedId}" ); } sw.Restart(); var mimisbrunnrSheet = states.GetSheet <MimisbrunnrSheet>(); if (!mimisbrunnrSheet.TryGetValue(stageId, out var mimisbrunnrSheetRow)) { throw new SheetRowNotFoundException(addressesHex, "MimisbrunnrSheet", stageId); } foreach (var equipmentId in equipments) { if (avatarState.inventory.TryGetNonFungibleItem(equipmentId, out ItemUsable itemUsable)) { var elementalType = ((Equipment)itemUsable).ElementalType; if (!mimisbrunnrSheetRow.ElementalTypes.Exists(x => x == elementalType)) { throw new InvalidElementalException( $"{addressesHex}ElementalType of {equipmentId} does not match."); } } } sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Check Equipments ElementalType: {Elapsed}", addressesHex, sw.Elapsed); avatarState.ValidateEquipments(equipments, context.BlockIndex); avatarState.ValidateConsumable(foods, context.BlockIndex); avatarState.ValidateCostume(costumes); sw.Restart(); if (avatarState.actionPoint < stageRow.CostAP) { throw new NotEnoughActionPointException( $"{addressesHex}Aborted due to insufficient action point: " + $"{avatarState.actionPoint} < {stageRow.CostAP}" ); } avatarState.actionPoint -= stageRow.CostAP; var equippableItem = new List <Guid>(); equippableItem.AddRange(costumes); equippableItem.AddRange(equipments); avatarState.EquipItems(equippableItem); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Unequip items: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var costumeStatSheet = states.GetSheet <CostumeStatSheet>(); var simulator = new StageSimulator( ctx.Random, avatarState, foods, worldId, stageId, states.GetStageSimulatorSheets(), costumeStatSheet ); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Initialize Simulator: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); simulator.Simulate(); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Simulator.Simulate(): {Elapsed}", addressesHex, sw.Elapsed); Log.Verbose( "{AddressesHex}Execute Mimisbrunnr({AvatarAddress}); worldId: {WorldId}, stageId: {StageId}, result: {Result}, " + "clearWave: {ClearWave}, totalWave: {TotalWave}", addressesHex, avatarAddress, worldId, stageId, simulator.Log.result, simulator.Log.clearedWaveNumber, simulator.Log.waveCount ); sw.Restart(); if (simulator.Log.IsClear) { simulator.Player.worldInformation.ClearStage( worldId, stageId, ctx.BlockIndex, worldSheet, worldUnlockSheet ); } sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr ClearStage: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); avatarState.Update(simulator); var materialSheet = states.GetSheet <MaterialItemSheet>(); avatarState.UpdateQuestRewards(materialSheet); avatarState.updatedAt = ctx.BlockIndex; avatarState.mailBox.CleanUp(); states = states.SetState(avatarAddress, avatarState.Serialize()); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Set AvatarState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (states.TryGetState(RankingMapAddress, out Dictionary d) && simulator.Log.IsClear) { var ranking = new RankingMapState(d); ranking.Update(avatarState); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Update RankingState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var serialized = ranking.Serialize(); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Serialize RankingState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); states = states.SetState(RankingMapAddress, serialized); } sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Set RankingState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (simulator.Log.stageId >= GameConfig.RequireClearedStageLevel.ActionsInRankingBoard && simulator.Log.IsClear && states.TryGetState(WeeklyArenaAddress, out Dictionary weeklyDict)) { var weekly = new WeeklyArenaState(weeklyDict); if (!weekly.Ended) { var characterSheet = states.GetSheet <CharacterSheet>(); if (weekly.ContainsKey(avatarAddress)) { var info = weekly[avatarAddress]; info.Update(avatarState, characterSheet, costumeStatSheet); weekly.Update(info); } else { weekly.SetV2(avatarState, characterSheet, costumeStatSheet); } sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Update WeeklyArenaState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var weeklySerialized = weekly.Serialize(); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Serialize RankingState: {Elapsed}", addressesHex, sw.Elapsed); states = states.SetState(weekly.address, weeklySerialized); } } Result = simulator.Log; var ended = DateTimeOffset.UtcNow; Log.Verbose("{AddressesHex}Mimisbrunnr Total Executed Time: {Elapsed}", addressesHex, ended - started); return(states); }
public override IAccountStateDelta Execute(IActionContext context) { IActionContext ctx = context; var states = ctx.PreviousStates; var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); if (ctx.Rehearsal) { states = states.SetState(rankingMapAddress, MarkChanged); states = states.SetState(avatarAddress, MarkChanged); states = states .SetState(inventoryAddress, MarkChanged) .SetState(worldInformationAddress, MarkChanged) .SetState(questListAddress, MarkChanged); return(states.SetState(ctx.Signer, MarkChanged)); } CheckObsolete(BlockChain.Policy.BlockPolicySource.V100086ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var sw = new Stopwatch(); sw.Start(); var started = DateTimeOffset.UtcNow; Log.Verbose("{AddressesHex}HAS exec started", addressesHex); if (!states.TryGetAvatarStateV2(ctx.Signer, avatarAddress, out AvatarState avatarState, out _)) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load."); } sw.Stop(); Log.Verbose("{AddressesHex}HAS Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (avatarState.RankingMapAddress != rankingMapAddress) { throw new InvalidAddressException($"{addressesHex}Invalid ranking map address"); } var worldSheet = states.GetSheet <WorldSheet>(); if (!worldSheet.TryGetValue(worldId, out var worldRow, false)) { throw new SheetRowNotFoundException(addressesHex, nameof(WorldSheet), worldId); } if (stageId < worldRow.StageBegin || stageId > worldRow.StageEnd) { throw new SheetRowColumnException( $"{addressesHex}{worldId} world is not contains {worldRow.Id} stage: " + $"{worldRow.StageBegin}-{worldRow.StageEnd}"); } var stageSheet = states.GetSheet <StageSheet>(); if (!stageSheet.TryGetValue(stageId, out var stageRow)) { throw new SheetRowNotFoundException(addressesHex, nameof(StageSheet), stageId); } var worldInformation = avatarState.worldInformation; if (!worldInformation.TryGetWorld(worldId, out var world)) { // NOTE: Add new World from WorldSheet worldInformation.AddAndUnlockNewWorld(worldRow, ctx.BlockIndex, worldSheet); } if (!world.IsUnlocked) { throw new InvalidWorldException($"{addressesHex}{worldId} is locked."); } if (world.StageBegin != worldRow.StageBegin || world.StageEnd != worldRow.StageEnd) { worldInformation.UpdateWorld(worldRow); } if (world.IsStageCleared && stageId > world.StageClearedId + 1 || !world.IsStageCleared && stageId != world.StageBegin) { throw new InvalidStageException( $"{addressesHex}Aborted as the stage ({worldId}/{stageId}) is not cleared; " + $"cleared stage: {world.StageClearedId}" ); } if (worldId == GameConfig.MimisbrunnrWorldId) { throw new InvalidWorldException($"{addressesHex}{worldId} can't execute HackAndSlash action."); } avatarState.ValidateEquipmentsV2(equipments, context.BlockIndex); avatarState.ValidateConsumable(foods, context.BlockIndex); avatarState.ValidateCostume(costumes); sw.Stop(); Log.Verbose("{AddressesHex}HAS Validate: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var costumeStatSheet = states.GetSheet <CostumeStatSheet>(); sw.Stop(); Log.Verbose("{AddressesHex}HAS get CostumeStatSheet: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (playCount <= 0) { throw new PlayCountIsZeroException($"{addressesHex}playCount must be greater than 0. " + $"current playCount : {playCount}"); } var totalCostActionPoint = stageRow.CostAP * playCount; if (avatarState.actionPoint < totalCostActionPoint) { throw new NotEnoughActionPointException( $"{addressesHex}Aborted due to insufficient action point: " + $"{avatarState.actionPoint} < totalAP({totalCostActionPoint}) = cost({stageRow.CostAP}) * boostCount({playCount})" ); } avatarState.actionPoint -= totalCostActionPoint; var items = equipments.Concat(costumes); avatarState.EquipItems(items); sw.Stop(); Log.Verbose("{AddressesHex}HAS Unequip items: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); // Update QuestList only when QuestSheet.Count is greater than QuestList.Count var questList = avatarState.questList; var questSheet = states.GetQuestSheet(); if (questList.Count() < questSheet.Count) { questList.UpdateListV1( 2, questSheet, states.GetSheet <QuestRewardSheet>(), states.GetSheet <QuestItemRewardSheet>(), states.GetSheet <EquipmentItemRecipeSheet>()); } sw.Stop(); Log.Verbose("{AddressesHex}HAS Update QuestList: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var simulator = new StageSimulator( ctx.Random, avatarState, foods, worldId, stageId, states.GetStageSimulatorSheets(), costumeStatSheet, StageSimulator.ConstructorVersionV100080, playCount); sw.Stop(); Log.Verbose("{AddressesHex}HAS Initialize Simulator: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); simulator.SimulateV5(playCount); sw.Stop(); Log.Verbose("{AddressesHex}HAS Simulator.SimulateV2(): {Elapsed}", addressesHex, sw.Elapsed); Log.Verbose( "{AddressesHex}Execute HackAndSlash({AvatarAddress}); worldId: {WorldId}, stageId: {StageId}, result: {Result}, " + "clearWave: {ClearWave}, totalWave: {TotalWave}", addressesHex, avatarAddress, worldId, stageId, simulator.Log.result, simulator.Log.clearedWaveNumber, simulator.Log.waveCount ); sw.Restart(); if (simulator.Log.IsClear) { var worldUnlockSheet = states.GetSheet <WorldUnlockSheet>(); simulator.Player.worldInformation.ClearStage( worldId, stageId, ctx.BlockIndex, worldSheet, worldUnlockSheet ); } sw.Stop(); Log.Verbose("{AddressesHex}HAS ClearStage: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); avatarState.Update(simulator); var materialSheet = states.GetSheet <MaterialItemSheet>(); avatarState.UpdateQuestRewards(materialSheet); avatarState.updatedAt = ctx.BlockIndex; avatarState.mailBox.CleanUp(); states = states .SetState(avatarAddress, avatarState.SerializeV2()) .SetState(inventoryAddress, avatarState.inventory.Serialize()) .SetState(worldInformationAddress, avatarState.worldInformation.Serialize()) .SetState(questListAddress, avatarState.questList.Serialize()); sw.Stop(); Log.Verbose("{AddressesHex}HAS Set AvatarState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (simulator.Log.IsClear && states.TryGetState(rankingMapAddress, out Dictionary d)) { var ranking = new RankingMapState(d); ranking.Update(avatarState); sw.Stop(); Log.Verbose("{AddressesHex}HAS Update RankingState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var serialized = ranking.Serialize(); sw.Stop(); Log.Verbose("{AddressesHex}HAS Serialize RankingState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); states = states.SetState(rankingMapAddress, serialized); } sw.Stop(); Log.Verbose("{AddressesHex}HAS Set RankingState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); TimeSpan totalElapsed = DateTimeOffset.UtcNow - started; Log.Verbose("{AddressesHex}HAS Total Executed Time: {Elapsed}", addressesHex, totalElapsed); return(states); }
public void Execute(int avatarLevel, int worldId, int stageId, bool contains) { Assert.True(_tableSheets.WorldSheet.TryGetValue(worldId, out var worldRow)); Assert.True(stageId >= worldRow.StageBegin); Assert.True(stageId <= worldRow.StageEnd); Assert.True(_tableSheets.StageSheet.TryGetValue(stageId, out _)); var previousAvatarState = _initialState.GetAvatarState(_avatarAddress); previousAvatarState.level = avatarLevel; previousAvatarState.worldInformation = new WorldInformation( 0, _tableSheets.WorldSheet, Math.Max(_tableSheets.StageSheet.First?.Id ?? 1, stageId - 1)); var costumeId = _tableSheets .CostumeItemSheet .Values .First(r => r.ItemSubType == ItemSubType.FullCostume) .Id; var costume = ItemFactory.CreateItem(_tableSheets.ItemSheet[costumeId], new TestRandom()); previousAvatarState.inventory.AddItem2(costume); var state = _initialState.SetState(_avatarAddress, previousAvatarState.Serialize()); var action = new HackAndSlash0() { costumes = new List <int> { costumeId }, equipments = new List <Guid>(), foods = new List <Guid>(), worldId = worldId, stageId = stageId, avatarAddress = _avatarAddress, WeeklyArenaAddress = _weeklyArenaState.address, RankingMapAddress = _rankingMapAddress, }; Assert.Null(action.Result); var nextState = action.Execute(new ActionContext() { PreviousStates = state, Signer = _agentAddress, Random = new TestRandom(), Rehearsal = false, }); var nextAvatarState = nextState.GetAvatarState(_avatarAddress); var newWeeklyState = nextState.GetWeeklyArenaState(0); Assert.NotNull(action.Result); Assert.NotEmpty(action.Result.OfType <GetReward>()); Assert.Equal(BattleLog.Result.Win, action.Result.result); Assert.Equal(contains, newWeeklyState.ContainsKey(_avatarAddress)); Assert.True(nextAvatarState.worldInformation.IsStageCleared(stageId)); var value = nextState.GetState(_rankingMapAddress); var rankingMapState = new RankingMapState((Dictionary)value); var info = rankingMapState.GetRankingInfos(null).First(); Assert.Equal(info.AgentAddress, _agentAddress); Assert.Equal(info.AvatarAddress, _avatarAddress); }
public override IAccountStateDelta Execute(IActionContext context) { IActionContext ctx = context; var states = ctx.PreviousStates; var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); if (ctx.Rehearsal) { states = states.SetState(rankingMapAddress, MarkChanged); states = states.SetState(avatarAddress, MarkChanged); states = states .SetState(inventoryAddress, MarkChanged) .SetState(worldInformationAddress, MarkChanged) .SetState(questListAddress, MarkChanged); return(states.SetState(ctx.Signer, MarkChanged)); } CheckObsolete(BlockChain.Policy.BlockPolicySource.V100086ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var sw = new Stopwatch(); sw.Start(); var started = DateTimeOffset.UtcNow; Log.Verbose("{AddressesHex}Mimisbrunnr exec started", addressesHex); if (!states.TryGetAvatarStateV2(ctx.Signer, avatarAddress, out AvatarState avatarState)) { throw new FailedLoadStateException("Aborted as the avatar state of the signer was failed to load."); } sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (avatarState.RankingMapAddress != rankingMapAddress) { throw new InvalidAddressException($"{addressesHex}Invalid ranking map address"); } var worldSheet = states.GetSheet <WorldSheet>(); if (!worldSheet.TryGetValue(worldId, out var worldRow, false)) { throw new SheetRowNotFoundException(addressesHex, nameof(WorldSheet), worldId); } if (stageId < worldRow.StageBegin || stageId > worldRow.StageEnd) { throw new SheetRowColumnException( $"{addressesHex}{worldId} world is not contains {worldRow.Id} stage: " + $"{worldRow.StageBegin}-{worldRow.StageEnd}"); } var stageSheet = states.GetSheet <StageSheet>(); if (!stageSheet.TryGetValue(stageId, out var stageRow)) { throw new SheetRowNotFoundException(addressesHex, nameof(StageSheet), stageId); } var worldUnlockSheet = states.GetSheet <WorldUnlockSheet>(); var worldInformation = avatarState.worldInformation; if (!worldInformation.TryGetWorld(worldId, out var world)) { // NOTE: Add new World from WorldSheet worldInformation.AddAndUnlockMimisbrunnrWorld(worldRow, ctx.BlockIndex, worldSheet, worldUnlockSheet); if (!worldInformation.TryGetWorld(worldId, out world)) { // Do nothing. } } if (!world.IsUnlocked) { var worldUnlockSheetRow = worldUnlockSheet.OrderedList.FirstOrDefault(row => row.WorldIdToUnlock == worldId); if (!(worldUnlockSheetRow is null) && worldInformation.IsWorldUnlocked(worldUnlockSheetRow.WorldId) && worldInformation.IsStageCleared(worldUnlockSheetRow.StageId)) { worldInformation.UnlockWorld(worldId, ctx.BlockIndex, worldSheet); if (!worldInformation.TryGetWorld(worldId, out world)) { // Do nothing. } } } if (!world.IsUnlocked) { throw new InvalidWorldException($"{addressesHex}{worldId} is locked."); } if (world.StageBegin != worldRow.StageBegin || world.StageEnd != worldRow.StageEnd) { worldInformation.UpdateWorld(worldRow); } if (world.IsStageCleared && stageId > world.StageClearedId + 1 || !world.IsStageCleared && stageId != world.StageBegin) { throw new InvalidStageException( $"{addressesHex}Aborted as the stage ({worldId}/{stageId}) is not cleared; " + $"cleared stage: {world.StageClearedId}" ); } sw.Restart(); var mimisbrunnrSheet = states.GetSheet <MimisbrunnrSheet>(); if (!mimisbrunnrSheet.TryGetValue(stageId, out var mimisbrunnrSheetRow)) { throw new SheetRowNotFoundException("MimisbrunnrSheet", addressesHex, stageId); } foreach (var equipmentId in equipments) { if (avatarState.inventory.TryGetNonFungibleItem(equipmentId, out ItemUsable itemUsable)) { var elementalType = ((Equipment)itemUsable).ElementalType; if (!mimisbrunnrSheetRow.ElementalTypes.Exists(x => x == elementalType)) { throw new InvalidElementalException( $"{addressesHex}ElementalType of {equipmentId} does not match."); } } } sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Check Equipments ElementalType: {Elapsed}", addressesHex, sw.Elapsed); avatarState.ValidateEquipmentsV2(equipments, context.BlockIndex); avatarState.ValidateConsumable(foods, context.BlockIndex); avatarState.ValidateCostume(costumes); sw.Restart(); if (playCount <= 0) { throw new PlayCountIsZeroException($"{addressesHex}playCount must be greater than 0. " + $"current playCount : {playCount}"); } var totalCostActionPoint = stageRow.CostAP * playCount; if (avatarState.actionPoint < totalCostActionPoint) { throw new NotEnoughActionPointException( $"{addressesHex}Aborted due to insufficient action point: " + $"{avatarState.actionPoint} < totalAP({totalCostActionPoint}) = cost({stageRow.CostAP}) * boostCount({playCount})" ); } avatarState.actionPoint -= totalCostActionPoint; var equippableItem = new List <Guid>(); equippableItem.AddRange(costumes); equippableItem.AddRange(equipments); avatarState.EquipItems(equippableItem); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Unequip items: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var costumeStatSheet = states.GetSheet <CostumeStatSheet>(); var simulator = new StageSimulator( ctx.Random, avatarState, foods, worldId, stageId, states.GetStageSimulatorSheets(), costumeStatSheet, StageSimulator.ConstructorVersionV100080, playCount); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Initialize Simulator: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); simulator.SimulateV5(playCount); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Simulator.Simulate(): {Elapsed}", addressesHex, sw.Elapsed); Log.Verbose( "{AddressesHex}Execute Mimisbrunnr({AvatarAddress}); worldId: {WorldId}, stageId: {StageId}, result: {Result}, " + "clearWave: {ClearWave}, totalWave: {TotalWave}", addressesHex, avatarAddress, worldId, stageId, simulator.Log.result, simulator.Log.clearedWaveNumber, simulator.Log.waveCount ); sw.Restart(); if (simulator.Log.IsClear) { simulator.Player.worldInformation.ClearStage( worldId, stageId, ctx.BlockIndex, worldSheet, worldUnlockSheet ); } sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr ClearStage: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); avatarState.Update(simulator); var materialSheet = states.GetSheet <MaterialItemSheet>(); avatarState.UpdateQuestRewards(materialSheet); avatarState.updatedAt = ctx.BlockIndex; avatarState.mailBox.CleanUp(); states = states .SetState(inventoryAddress, avatarState.inventory.Serialize()) .SetState(worldInformationAddress, avatarState.worldInformation.Serialize()) .SetState(questListAddress, avatarState.questList.Serialize()) .SetState(avatarAddress, avatarState.SerializeV2()); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Set AvatarState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (simulator.Log.IsClear && states.TryGetState(rankingMapAddress, out Dictionary d)) { var ranking = new RankingMapState(d); ranking.Update(avatarState); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Update RankingState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var serialized = ranking.Serialize(); sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Serialize RankingState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); states = states.SetState(rankingMapAddress, serialized); } sw.Stop(); Log.Verbose("{AddressesHex}Mimisbrunnr Set RankingState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var ended = DateTimeOffset.UtcNow; Log.Verbose("{AddressesHex}Mimisbrunnr Total Executed Time: {Elapsed}", addressesHex, ended - started); return(states); }