public void Execute_Backward_Compatible(bool isNew, bool avatarBackward, bool enemyBackward) { var previousWeeklyState = _initialState.GetWeeklyArenaState(ArenaIndex); var previousAvatar1State = _initialState.GetAvatarState(_avatar1Address); previousAvatar1State.level = 10; var prevScore = previousWeeklyState[_avatar1Address].Score; if (isNew) { previousWeeklyState.Remove(_avatar1Address); } var previousState = _initialState.SetState( _avatar1Address, previousAvatar1State.Serialize()); var itemIds = _tableSheets.WeeklyArenaRewardSheet.Values .Select(r => r.Reward.ItemId) .ToList(); Assert.All(itemIds, id => Assert.False(previousAvatar1State.inventory.HasItem(id))); var row = _tableSheets.CostumeStatSheet.Values.First(r => r.StatType == StatType.ATK); var costume = (Costume)ItemFactory.CreateItem( _tableSheets.ItemSheet[row.CostumeId], new TestRandom()); costume.equipped = true; previousAvatar1State.inventory.AddItem(costume); var row2 = _tableSheets.CostumeStatSheet.Values.First(r => r.StatType == StatType.DEF); var enemyCostume = (Costume)ItemFactory.CreateItem( _tableSheets.ItemSheet[row2.CostumeId], new TestRandom()); enemyCostume.equipped = true; var enemyAvatarState = _initialState.GetAvatarState(_avatar2Address); enemyAvatarState.inventory.AddItem(enemyCostume); Address worldInformationAddress = _avatar1Address.Derive(LegacyWorldInformationKey); if (avatarBackward) { previousState = previousState.SetState(_avatar1Address, previousAvatar1State.Serialize()); } else { previousState = previousState .SetState( _avatar1Address.Derive(LegacyInventoryKey), previousAvatar1State.inventory.Serialize()) .SetState( worldInformationAddress, previousAvatar1State.worldInformation.Serialize()) .SetState( _avatar1Address.Derive(LegacyQuestListKey), previousAvatar1State.questList.Serialize()) .SetState(_avatar1Address, previousAvatar1State.SerializeV2()); } if (enemyBackward) { previousState = previousState.SetState(_avatar2Address, enemyAvatarState.Serialize()); } else { previousState = previousState .SetState( _avatar2Address.Derive(LegacyInventoryKey), enemyAvatarState.inventory.Serialize()) .SetState( _avatar2Address.Derive(LegacyWorldInformationKey), enemyAvatarState.worldInformation.Serialize()) .SetState( _avatar2Address.Derive(LegacyQuestListKey), enemyAvatarState.questList.Serialize()) .SetState(_avatar2Address, enemyAvatarState.SerializeV2()); } var action = new RankingBattle { avatarAddress = _avatar1Address, enemyAddress = _avatar2Address, weeklyArenaAddress = _weeklyArenaAddress, costumeIds = new List <Guid> { costume.ItemId }, equipmentIds = new List <Guid>(), }; var nextState = action.Execute(new ActionContext { PreviousStates = previousState, Signer = _agent1Address, Random = new TestRandom(), Rehearsal = false, BlockIndex = RankingBattle.UpdateTargetBlockIndex - 1, }); var nextAvatar1State = nextState.GetAvatarStateV2(_avatar1Address); var nextWeeklyState = nextState.GetWeeklyArenaState(ArenaIndex); var nextArenaInfo = nextWeeklyState[_avatar1Address]; Assert.Contains(nextAvatar1State.inventory.Materials, i => itemIds.Contains(i.Id)); Assert.NotNull(action.ArenaInfo); Assert.NotNull(action.EnemyArenaInfo); Assert.True(nextArenaInfo.Score > prevScore); // Check simulation result equal. var player = new Player( previousAvatar1State, _tableSheets.CharacterSheet, _tableSheets.CharacterLevelSheet, _tableSheets.EquipmentItemSetEffectSheet); var simulator = new RankingSimulator( new TestRandom(), player, action.EnemyPlayerDigest, new List <Guid>(), _tableSheets.GetRankingSimulatorSheets(), RankingBattle.StageId, action.ArenaInfo, action.EnemyArenaInfo, _tableSheets.CostumeStatSheet); simulator.Simulate(); Assert.Equal(nextArenaInfo.Score, simulator.Log.score); Assert.Equal(previousAvatar1State.SerializeV2(), nextAvatar1State.SerializeV2()); Assert.Equal(previousAvatar1State.worldInformation.Serialize(), nextAvatar1State.worldInformation.Serialize()); }
public void Execute(bool isNew, bool avatarBackward, bool enemyBackward) { var previousWeeklyState = _initialState.GetWeeklyArenaState(0); var previousAvatar1State = _initialState.GetAvatarState(_avatar1Address); previousAvatar1State.level = 10; var prevScore = previousWeeklyState[_avatar1Address].Score; if (isNew) { previousWeeklyState.Remove(_avatar1Address); } var previousState = _initialState.SetState( _avatar1Address, previousAvatar1State.Serialize()); var itemIds = _tableSheets.WeeklyArenaRewardSheet.Values .Select(r => r.Reward.ItemId) .ToList(); Assert.All(itemIds, id => Assert.False(previousAvatar1State.inventory.HasItem(id))); var row = _tableSheets.CostumeStatSheet.Values.First(r => r.StatType == StatType.ATK); var costume = (Costume)ItemFactory.CreateItem( _tableSheets.ItemSheet[row.CostumeId], new TestRandom()); costume.equipped = true; previousAvatar1State.inventory.AddItem(costume); var row2 = _tableSheets.CostumeStatSheet.Values.First(r => r.StatType == StatType.DEF); var enemyCostume = (Costume)ItemFactory.CreateItem( _tableSheets.ItemSheet[row2.CostumeId], new TestRandom()); enemyCostume.equipped = true; var enemyAvatarState = _initialState.GetAvatarState(_avatar2Address); enemyAvatarState.inventory.AddItem(enemyCostume); if (avatarBackward) { previousState = previousState.SetState(_avatar1Address, previousAvatar1State.Serialize()); } else { previousState = previousState .SetState( _avatar1Address.Derive(LegacyInventoryKey), previousAvatar1State.inventory.Serialize()) .SetState( _avatar1Address.Derive(LegacyWorldInformationKey), previousAvatar1State.worldInformation.Serialize()) .SetState( _avatar1Address.Derive(LegacyQuestListKey), previousAvatar1State.questList.Serialize()) .SetState(_avatar1Address, previousAvatar1State.SerializeV2()); } if (enemyBackward) { previousState = previousState.SetState(_avatar2Address, enemyAvatarState.Serialize()); } else { previousState = previousState .SetState( _avatar2Address.Derive(LegacyInventoryKey), enemyAvatarState.inventory.Serialize()) .SetState( _avatar2Address.Derive(LegacyWorldInformationKey), enemyAvatarState.worldInformation.Serialize()) .SetState( _avatar2Address.Derive(LegacyQuestListKey), enemyAvatarState.questList.Serialize()) .SetState(_avatar2Address, enemyAvatarState.SerializeV2()); } var action = new RankingBattle8 { avatarAddress = _avatar1Address, enemyAddress = _avatar2Address, weeklyArenaAddress = _weeklyArenaAddress, costumeIds = new List <Guid> { costume.ItemId }, equipmentIds = new List <Guid>(), consumableIds = new List <Guid>(), }; Assert.Null(action.Result); var nextState = action.Execute(new ActionContext() { PreviousStates = previousState, Signer = _agent1Address, Random = new TestRandom(), Rehearsal = false, }); var nextAvatar1State = nextState.GetAvatarStateV2(_avatar1Address); var nextWeeklyState = nextState.GetWeeklyArenaState(0); Assert.Contains(nextAvatar1State.inventory.Materials, i => itemIds.Contains(i.Id)); Assert.NotNull(action.Result); Assert.NotNull(action.ArenaInfo); Assert.NotNull(action.EnemyArenaInfo); Assert.NotNull(action.EnemyAvatarState); Assert.Contains(typeof(GetReward), action.Result.Select(e => e.GetType())); Assert.Equal(BattleLog.Result.Win, action.Result.result); Assert.True(nextWeeklyState[_avatar1Address].Score > prevScore); // Check simulation result equal. var simulator = new RankingSimulator( new TestRandom(), previousAvatar1State, action.EnemyAvatarState, action.consumableIds, _tableSheets.GetRankingSimulatorSheets(), RankingBattle8.StageId, action.ArenaInfo, action.EnemyArenaInfo, _tableSheets.CostumeStatSheet); simulator.Simulate(); BattleLog log = simulator.Log; BattleLog result = action.Result; Assert.Equal(result.score, log.score); Assert.Equal(result.Count, log.Count); Assert.Equal(result.result, log.result); }
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)); } var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress, EnemyAddress); var sw = new Stopwatch(); sw.Start(); var started = DateTimeOffset.UtcNow; Log.Verbose( "{AddressesHex}RankingBattle exec started. costume: ({CostumeIds}), equipment: ({EquipmentIds})", addressesHex, string.Join(",", costumeIds), string.Join(",", equipmentIds) ); if (AvatarAddress.Equals(EnemyAddress)) { throw new InvalidAddressException($"{addressesHex}Aborted as the signer tried to battle for themselves."); } if (!states.TryGetAvatarState(ctx.Signer, AvatarAddress, out var avatarState)) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load."); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); avatarState.ValidateEquipments(equipmentIds, context.BlockIndex); avatarState.ValidateConsumable(consumableIds, context.BlockIndex); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Validate Equipments: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world) || world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard) { throw new NotEnoughClearedStageLevelException( addressesHex, GameConfig.RequireClearedStageLevel.ActionsInRankingBoard, world.StageClearedId); } avatarState.EquipCostumes(new HashSet <int>(costumeIds)); avatarState.EquipEquipments(equipmentIds); avatarState.ValidateCostume(new HashSet <int>(costumeIds)); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Equip Equipments: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var enemyAvatarState = states.GetAvatarState(EnemyAddress); if (enemyAvatarState is null) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the opponent ({EnemyAddress}) was failed to load."); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get Enemy AvatarState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var weeklyArenaState = states.GetWeeklyArenaState(WeeklyArenaAddress); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get WeeklyArenaState ({Address}): {Elapsed}", addressesHex, WeeklyArenaAddress, sw.Elapsed); sw.Restart(); if (weeklyArenaState.Ended) { throw new WeeklyArenaStateAlreadyEndedException( addressesHex + WeeklyArenaStateAlreadyEndedException.BaseMessage); } if (!weeklyArenaState.ContainsKey(AvatarAddress)) { throw new WeeklyArenaStateNotContainsAvatarAddressException(addressesHex, AvatarAddress); } var arenaInfo = weeklyArenaState[AvatarAddress]; if (arenaInfo.DailyChallengeCount <= 0) { throw new NotEnoughWeeklyArenaChallengeCountException( addressesHex + NotEnoughWeeklyArenaChallengeCountException.BaseMessage); } if (!arenaInfo.Active) { arenaInfo.Activate(); } if (!weeklyArenaState.ContainsKey(EnemyAddress)) { throw new WeeklyArenaStateNotContainsAvatarAddressException(addressesHex, EnemyAddress); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Validate ArenaInfo: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var costumeStatSheet = states.GetSheet <CostumeStatSheet>(); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get CostumeStatSheet: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var simulator = new RankingSimulator( ctx.Random, avatarState, enemyAvatarState, consumableIds, states.GetRankingSimulatorSheets(), StageId, arenaInfo, weeklyArenaState[EnemyAddress], costumeStatSheet); simulator.Simulate(); sw.Stop(); Log.Verbose( "{AddressesHex}RankingBattle Simulate() with equipment:({Equipment}), costume:({Costume}): {Elapsed}", addressesHex, string.Join(",", simulator.Player.Equipments.Select(r => r.ItemId)), string.Join(",", simulator.Player.Costumes.Select(r => r.ItemId)), sw.Elapsed ); Log.Verbose( "{AddressesHex}Execute RankingBattle({AvatarAddress}); result: {Result} event count: {EventCount}", addressesHex, AvatarAddress, simulator.Log.result, simulator.Log.Count ); sw.Restart(); Result = simulator.Log; foreach (var itemBase in simulator.Reward.OrderBy(i => i.Id)) { Log.Verbose( "{AddressesHex}RankingBattle Add Reward Item({ItemBaseId}): {Elapsed}", addressesHex, itemBase.Id, sw.Elapsed); avatarState.inventory.AddItem(itemBase); } states = states.SetState(WeeklyArenaAddress, weeklyArenaState.Serialize()); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Serialize WeeklyArenaState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); states = states.SetState(AvatarAddress, avatarState.Serialize()); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Serialize AvatarState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var ended = DateTimeOffset.UtcNow; Log.Verbose("{AddressesHex}RankingBattle Total Executed Time: {Elapsed}", addressesHex, ended - started); return(states); }
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)) { throw new InvalidAddressException("Aborted as the signer tried to battle for themselves."); } if (!states.TryGetAvatarState(ctx.Signer, AvatarAddress, out var avatarState)) { throw new FailedLoadStateException("Aborted as the avatar state of the signer was failed to load."); } avatarState.ValidateEquipments(equipmentIds, context.BlockIndex); avatarState.ValidateConsumable(consumableIds, context.BlockIndex); if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world) || world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard) { throw new NotEnoughClearedStageLevelException( GameConfig.RequireClearedStageLevel.ActionsInRankingBoard, world.StageClearedId); } avatarState.EquipCostumes(new HashSet <int>(costumeIds)); avatarState.EquipEquipments(equipmentIds); avatarState.ValidateCostume(new HashSet <int>(costumeIds)); var enemyAvatarState = states.GetAvatarState(EnemyAddress); if (enemyAvatarState is null) { throw new FailedLoadStateException($"Aborted as the avatar state of the opponent ({EnemyAddress}) was failed to load."); } var weeklyArenaState = states.GetWeeklyArenaState(WeeklyArenaAddress); if (weeklyArenaState.Ended) { throw new WeeklyArenaStateAlreadyEndedException(); } if (!weeklyArenaState.ContainsKey(AvatarAddress)) { throw new WeeklyArenaStateNotContainsAvatarAddressException(AvatarAddress); } var arenaInfo = weeklyArenaState[AvatarAddress]; if (arenaInfo.DailyChallengeCount <= 0) { throw new NotEnoughWeeklyArenaChallengeCountException(); } if (!arenaInfo.Active) { arenaInfo.Activate(); } if (!weeklyArenaState.ContainsKey(EnemyAddress)) { throw new WeeklyArenaStateNotContainsAvatarAddressException(EnemyAddress); } Log.Debug(weeklyArenaState.address.ToHex()); var costumeStatSheet = states.GetSheet <CostumeStatSheet>(); var simulator = new RankingSimulator( ctx.Random, avatarState, enemyAvatarState, consumableIds, states.GetRankingSimulatorSheets(), StageId, arenaInfo, weeklyArenaState[EnemyAddress], costumeStatSheet); simulator.Simulate(); Result = simulator.Log; foreach (var itemBase in simulator.Reward.OrderBy(i => i.Id)) { avatarState.inventory.AddItem(itemBase); } return(states .SetState(WeeklyArenaAddress, weeklyArenaState.Serialize()) .SetState(AvatarAddress, avatarState.Serialize())); }
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) { return(states .SetState(avatarAddress, MarkChanged) .SetState(weeklyArenaAddress, MarkChanged) .SetState(inventoryAddress, MarkChanged) .SetState(worldInformationAddress, MarkChanged) .SetState(questListAddress, MarkChanged)); } // Avoid InvalidBlockStateRootHashException if (ctx.BlockIndex == 680341 && Id.Equals(new Guid("df37dbd8-5703-4dff-918b-ad22ee4c34c6"))) { return(states); } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress, enemyAddress); var sw = new Stopwatch(); sw.Start(); var started = DateTimeOffset.UtcNow; Log.Verbose( "{AddressesHex}RankingBattle exec started. costume: ({CostumeIds}), equipment: ({EquipmentIds})", addressesHex, string.Join(",", costumeIds), string.Join(",", equipmentIds) ); if (avatarAddress.Equals(enemyAddress)) { throw new InvalidAddressException($"{addressesHex}Aborted as the signer tried to battle for themselves."); } if (!states.TryGetAvatarStateV2(ctx.Signer, avatarAddress, out var avatarState)) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load."); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var items = equipmentIds.Concat(costumeIds); avatarState.ValidateEquipmentsV2(equipmentIds, context.BlockIndex); avatarState.ValidateConsumable(consumableIds, context.BlockIndex); avatarState.ValidateCostume(costumeIds); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Validate Equipments: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); avatarState.EquipItems(items); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Equip Equipments: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world) || world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard) { throw new NotEnoughClearedStageLevelException( addressesHex, GameConfig.RequireClearedStageLevel.ActionsInRankingBoard, world.StageClearedId); } AvatarState enemyAvatarState; try { enemyAvatarState = states.GetAvatarStateV2(enemyAddress); } // BackWard compatible. catch (FailedLoadStateException) { enemyAvatarState = states.GetAvatarState(enemyAddress); } if (enemyAvatarState is null) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the opponent ({enemyAddress}) was failed to load."); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get Enemy AvatarState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var weeklyArenaState = states.GetWeeklyArenaState(weeklyArenaAddress); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get WeeklyArenaState ({Address}): {Elapsed}", addressesHex, weeklyArenaAddress, sw.Elapsed); sw.Restart(); if (weeklyArenaState.Ended) { throw new WeeklyArenaStateAlreadyEndedException(); } var costumeStatSheet = states.GetSheet <CostumeStatSheet>(); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get CostumeStatSheet: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (!weeklyArenaState.ContainsKey(avatarAddress)) { var characterSheet = states.GetSheet <CharacterSheet>(); weeklyArenaState.SetV2(avatarState, characterSheet, costumeStatSheet); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Set AvatarInfo: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); } var arenaInfo = weeklyArenaState[avatarAddress]; if (arenaInfo.DailyChallengeCount <= 0) { throw new NotEnoughWeeklyArenaChallengeCountException( addressesHex + NotEnoughWeeklyArenaChallengeCountException.BaseMessage); } if (!arenaInfo.Active) { arenaInfo.Activate(); } if (!weeklyArenaState.ContainsKey(enemyAddress)) { throw new WeeklyArenaStateNotContainsAvatarAddressException(addressesHex, enemyAddress); } var enemyArenaInfo = weeklyArenaState[enemyAddress]; if (!enemyArenaInfo.Active) { enemyArenaInfo.Activate(); } Log.Verbose("{WeeklyArenaStateAddress}", weeklyArenaState.address.ToHex()); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Validate ArenaInfo: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var simulator = new RankingSimulator( ctx.Random, avatarState, enemyAvatarState, consumableIds, states.GetRankingSimulatorSheets(), StageId, arenaInfo, enemyArenaInfo, costumeStatSheet); simulator.Simulate(); sw.Stop(); Log.Verbose( "{AddressesHex}RankingBattle Simulate() with equipment:({Equipment}), costume:({Costume}): {Elapsed}", addressesHex, string.Join(",", simulator.Player.Equipments.Select(r => r.ItemId)), string.Join(",", simulator.Player.Costumes.Select(r => r.ItemId)), sw.Elapsed ); Log.Verbose( "{AddressesHex}Execute RankingBattle({AvatarAddress}); result: {Result} event count: {EventCount}", addressesHex, avatarAddress, simulator.Log.result, simulator.Log.Count ); sw.Restart(); Result = simulator.Log; foreach (var itemBase in simulator.Reward.OrderBy(i => i.Id)) { Log.Verbose( "{AddressesHex}RankingBattle Add Reward Item({ItemBaseId}): {Elapsed}", addressesHex, itemBase.Id, sw.Elapsed); avatarState.inventory.AddItem(itemBase); } states = states.SetState(weeklyArenaAddress, weeklyArenaState.Serialize()); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Serialize WeeklyArenaState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); 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}RankingBattle Serialize AvatarState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var ended = DateTimeOffset.UtcNow; Log.Verbose("{AddressesHex}RankingBattle 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) { return(states .SetState(avatarAddress, MarkChanged) .SetState(weeklyArenaAddress, MarkChanged) .SetState(inventoryAddress, MarkChanged) .SetState(worldInformationAddress, MarkChanged) .SetState(questListAddress, MarkChanged)); } // Avoid InvalidBlockStateRootHashException if (ctx.BlockIndex == 680341 && Id.Equals(new Guid("df37dbd8-5703-4dff-918b-ad22ee4c34c6"))) { return(states); } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress, enemyAddress); var sw = new Stopwatch(); sw.Start(); var started = DateTimeOffset.UtcNow; Log.Verbose( "{AddressesHex}RankingBattle exec started. costume: ({CostumeIds}), equipment: ({EquipmentIds})", addressesHex, string.Join(",", costumeIds), string.Join(",", equipmentIds) ); if (avatarAddress.Equals(enemyAddress)) { throw new InvalidAddressException($"{addressesHex}Aborted as the signer tried to battle for themselves."); } if (!states.TryGetAvatarStateV2(ctx.Signer, avatarAddress, out var avatarState, out bool migrationRequired)) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load."); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var sheets = states.GetSheets( containRankingSimulatorSheets: true, sheetTypes: new[] { typeof(CharacterSheet), typeof(CostumeStatSheet), }); sw.Stop(); Log.Verbose("{AddressesHex}HAS Get Sheets: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var items = equipmentIds.Concat(costumeIds); avatarState.ValidateEquipmentsV2(equipmentIds, context.BlockIndex); avatarState.ValidateCostume(costumeIds); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Validate Equipments: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); avatarState.EquipItems(items); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Equip Equipments: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world) || world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard) { throw new NotEnoughClearedStageLevelException( addressesHex, GameConfig.RequireClearedStageLevel.ActionsInRankingBoard, world.StageClearedId); } AvatarState enemyAvatarState; try { enemyAvatarState = states.GetAvatarStateV2(enemyAddress); } // BackWard compatible. catch (FailedLoadStateException) { enemyAvatarState = states.GetAvatarState(enemyAddress); } if (enemyAvatarState is null) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the opponent ({enemyAddress}) was failed to load."); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get Enemy AvatarState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (!states.TryGetState(weeklyArenaAddress, out Dictionary rawWeeklyArenaState)) { return(states); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get WeeklyArenaState ({Address}): {Elapsed}", addressesHex, weeklyArenaAddress, sw.Elapsed); sw.Restart(); bool arenaEnded = rawWeeklyArenaState["ended"].ToBoolean(); Dictionary weeklyArenaMap = (Dictionary)rawWeeklyArenaState["map"]; if (arenaEnded) { throw new WeeklyArenaStateAlreadyEndedException(); } var costumeStatSheet = sheets.GetSheet <CostumeStatSheet>(); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get CostumeStatSheet: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); IKey arenaKey = (IKey)avatarAddress.Serialize(); if (!weeklyArenaMap.ContainsKey(arenaKey)) { var characterSheet = sheets.GetSheet <CharacterSheet>(); var newInfo = new ArenaInfo(avatarState, characterSheet, costumeStatSheet, false); weeklyArenaMap = (Dictionary)weeklyArenaMap.Add(arenaKey, newInfo.Serialize()); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Set AvatarInfo: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); } var arenaInfo = new ArenaInfo((Dictionary)weeklyArenaMap[arenaKey]); if (arenaInfo.DailyChallengeCount <= 0) { throw new NotEnoughWeeklyArenaChallengeCountException( addressesHex + NotEnoughWeeklyArenaChallengeCountException.BaseMessage); } if (!arenaInfo.Active) { arenaInfo.Activate(); } IKey enemyKey = (IKey)enemyAddress.Serialize(); if (!weeklyArenaMap.ContainsKey(enemyKey)) { throw new WeeklyArenaStateNotContainsAvatarAddressException(addressesHex, enemyAddress); } var enemyArenaInfo = new ArenaInfo((Dictionary)weeklyArenaMap[enemyKey]); if (!enemyArenaInfo.Active) { enemyArenaInfo.Activate(); } Log.Verbose("{WeeklyArenaStateAddress}", weeklyArenaAddress.ToHex()); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Validate ArenaInfo: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); ArenaInfo = new ArenaInfo((Dictionary)weeklyArenaMap[arenaKey]); EnemyArenaInfo = new ArenaInfo((Dictionary)weeklyArenaMap[enemyKey]); var rankingSheets = sheets.GetRankingSimulatorSheets(); var player = new Player(avatarState, rankingSheets); var enemyPlayerDigest = new EnemyPlayerDigest(enemyAvatarState); var simulator = new RankingSimulator( ctx.Random, player, enemyPlayerDigest, new List <Guid>(), rankingSheets, StageId, arenaInfo, enemyArenaInfo, costumeStatSheet); simulator.Simulate(); sw.Stop(); Log.Verbose( "{AddressesHex}RankingBattle Simulate() with equipment:({Equipment}), costume:({Costume}): {Elapsed}", addressesHex, string.Join(",", simulator.Player.Equipments.Select(r => r.ItemId)), string.Join(",", simulator.Player.Costumes.Select(r => r.ItemId)), sw.Elapsed ); Log.Verbose( "{AddressesHex}Execute RankingBattle({AvatarAddress}); result: {Result} event count: {EventCount}", addressesHex, avatarAddress, simulator.Log.result, simulator.Log.Count ); sw.Restart(); foreach (var itemBase in simulator.Reward.OrderBy(i => i.Id)) { Log.Verbose( "{AddressesHex}RankingBattle Add Reward Item({ItemBaseId}): {Elapsed}", addressesHex, itemBase.Id, sw.Elapsed); avatarState.inventory.AddItem(itemBase); } var arenaMapDict = new Dictionary <IKey, IValue>(); foreach (var kv in weeklyArenaMap) { var key = kv.Key; var value = kv.Value; if (key.Equals(arenaKey)) { value = arenaInfo.Serialize(); } if (key.Equals(enemyKey)) { value = enemyArenaInfo.Serialize(); } arenaMapDict[key] = value; } var weeklyArenaDict = new Dictionary <IKey, IValue>(); foreach (var kv in rawWeeklyArenaState) { weeklyArenaDict[kv.Key] = kv.Key.Equals((Text)"map") ? new Dictionary(arenaMapDict) : kv.Value; } states = states.SetState(weeklyArenaAddress, new Dictionary(weeklyArenaDict)); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Serialize WeeklyArenaState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); states = states .SetState(inventoryAddress, avatarState.inventory.Serialize()) .SetState(questListAddress, avatarState.questList.Serialize()); if (migrationRequired) { states = states .SetState(worldInformationAddress, avatarState.worldInformation.Serialize()) .SetState(avatarAddress, avatarState.SerializeV2()); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Serialize AvatarState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var ended = DateTimeOffset.UtcNow; Log.Verbose("{AddressesHex}RankingBattle Total Executed Time: {Elapsed}", addressesHex, ended - started); EnemyPlayerDigest = enemyPlayerDigest; return(states); }
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)); } var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress, EnemyAddress); Log.Warning("ranking_battle is deprecated. Please use ranking_battle2"); if (AvatarAddress.Equals(EnemyAddress)) { throw new InvalidAddressException($"{addressesHex}Aborted as the signer tried to battle for themselves."); } if (!states.TryGetAgentAvatarStates( ctx.Signer, AvatarAddress, out var agentState, out var avatarState)) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load."); } var costumes = new HashSet <int>(costumeIds); avatarState.ValidateEquipments(equipmentIds, context.BlockIndex); avatarState.ValidateConsumable(consumableIds, context.BlockIndex); avatarState.ValidateCostume(costumes); if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world) || world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard) { throw new NotEnoughClearedStageLevelException( addressesHex, GameConfig.RequireClearedStageLevel.ActionsInRankingBoard, world.StageClearedId); } avatarState.EquipCostumes(costumes); avatarState.EquipEquipments(equipmentIds); var enemyAvatarState = states.GetAvatarState(EnemyAddress); if (enemyAvatarState is null) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the opponent ({EnemyAddress}) was failed to load."); } var weeklyArenaState = states.GetWeeklyArenaState(WeeklyArenaAddress); if (weeklyArenaState.Ended) { throw new WeeklyArenaStateAlreadyEndedException( addressesHex + WeeklyArenaStateAlreadyEndedException.BaseMessage); } if (!weeklyArenaState.ContainsKey(AvatarAddress)) { throw new WeeklyArenaStateNotContainsAvatarAddressException(addressesHex, AvatarAddress); } var arenaInfo = weeklyArenaState[AvatarAddress]; if (arenaInfo.DailyChallengeCount <= 0) { throw new NotEnoughWeeklyArenaChallengeCountException( addressesHex + NotEnoughWeeklyArenaChallengeCountException.BaseMessage); } if (!arenaInfo.Active) { FungibleAssetValue agentBalance = default; try { agentBalance = states.GetBalance(ctx.Signer, states.GetGoldCurrency()); } catch (InvalidOperationException) { throw new NotEnoughFungibleAssetValueException(addressesHex, EntranceFee, agentBalance); } if (agentBalance >= new FungibleAssetValue(agentBalance.Currency, EntranceFee, 0)) { states = states.TransferAsset( ctx.Signer, WeeklyArenaAddress, new FungibleAssetValue( states.GetGoldCurrency(), EntranceFee, 0 ) ); arenaInfo.Activate(); } else { throw new NotEnoughFungibleAssetValueException(addressesHex, EntranceFee, agentBalance); } } if (!weeklyArenaState.ContainsKey(EnemyAddress)) { throw new WeeklyArenaStateNotContainsAvatarAddressException(addressesHex, EnemyAddress); } Log.Verbose("{WeeklyArenaStateAddress}", weeklyArenaState.address.ToHex()); var simulator = new RankingSimulator( ctx.Random, avatarState, enemyAvatarState, consumableIds, states.GetRankingSimulatorSheets(), StageId, arenaInfo, weeklyArenaState[EnemyAddress]); simulator.Simulate(); Result = simulator.Log; foreach (var itemBase in simulator.Reward.OrderBy(i => i.Id)) { avatarState.inventory.AddItem(itemBase); } return(states .SetState(ctx.Signer, agentState.Serialize()) .SetState(WeeklyArenaAddress, weeklyArenaState.Serialize()) .SetState(AvatarAddress, avatarState.Serialize())); }
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())); }
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) { return(states .SetState(avatarAddress, MarkChanged) .SetState(weeklyArenaAddress, MarkChanged) .SetState(inventoryAddress, MarkChanged) .SetState(worldInformationAddress, MarkChanged) .SetState(questListAddress, MarkChanged)); } // Avoid InvalidBlockStateRootHashException if (ctx.BlockIndex == 680341 && Id.Equals(new Guid("df37dbd8-5703-4dff-918b-ad22ee4c34c6"))) { return(states); } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress, enemyAddress); var sw = new Stopwatch(); sw.Start(); var started = DateTimeOffset.UtcNow; Log.Verbose( "{AddressesHex}RankingBattle exec started. costume: ({CostumeIds}), equipment: ({EquipmentIds})", addressesHex, string.Join(",", costumeIds), string.Join(",", equipmentIds) ); if (avatarAddress.Equals(enemyAddress)) { throw new InvalidAddressException($"{addressesHex}Aborted as the signer tried to battle for themselves."); } if (!states.TryGetAvatarStateV2(ctx.Signer, avatarAddress, out var avatarState, out bool migrationRequired)) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load."); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get AgentAvatarStates: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var sheets = states.GetSheets( containRankingSimulatorSheets: true, sheetTypes: new[] { typeof(CharacterSheet), typeof(CostumeStatSheet), }); sw.Stop(); Log.Verbose("{AddressesHex}HAS Get Sheets: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var items = equipmentIds.Concat(costumeIds); avatarState.ValidateEquipmentsV2(equipmentIds, context.BlockIndex); avatarState.ValidateCostume(costumeIds); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Validate Equipments: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); avatarState.EquipItems(items); sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Equip Equipments: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); if (!avatarState.worldInformation.TryGetUnlockedWorldByStageClearedBlockIndex(out var world) || world.StageClearedId < GameConfig.RequireClearedStageLevel.ActionsInRankingBoard) { throw new NotEnoughClearedStageLevelException( addressesHex, GameConfig.RequireClearedStageLevel.ActionsInRankingBoard, world.StageClearedId); } AvatarState enemyAvatarState; try { enemyAvatarState = states.GetAvatarStateV2(enemyAddress); } // BackWard compatible. catch (FailedLoadStateException) { enemyAvatarState = states.GetAvatarState(enemyAddress); } if (enemyAvatarState is null) { throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the opponent ({enemyAddress}) was failed to load."); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get Enemy AvatarState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var costumeStatSheet = sheets.GetSheet <CostumeStatSheet>(); if (!states.TryGetState(weeklyArenaAddress, out Dictionary rawWeeklyArenaState)) { return(states); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Get WeeklyArenaState ({Address}): {Elapsed}", addressesHex, weeklyArenaAddress, sw.Elapsed); sw.Restart(); bool arenaEnded = rawWeeklyArenaState["ended"].ToBoolean(); if (arenaEnded) { throw new WeeklyArenaStateAlreadyEndedException(); } if (context.BlockIndex >= UpdateTargetBlockIndex) { // Run updated model var arenaInfoAddress = weeklyArenaAddress.Derive(avatarAddress.ToByteArray()); ArenaInfo arenaInfo; var characterSheet = sheets.GetSheet <CharacterSheet>(); var addressListAddress = weeklyArenaAddress.Derive("address_list"); bool listCheck = false; if (!states.TryGetState(arenaInfoAddress, out Dictionary rawArenaInfo)) { arenaInfo = new ArenaInfo(avatarState, characterSheet, costumeStatSheet, true); listCheck = true; rawArenaInfo = (Dictionary)arenaInfo.Serialize(); } else { arenaInfo = new ArenaInfo(rawArenaInfo); } var enemyInfoAddress = weeklyArenaAddress.Derive(enemyAddress.ToByteArray()); ArenaInfo enemyInfo; if (!states.TryGetState(enemyInfoAddress, out Dictionary rawEnemyInfo)) { enemyInfo = new ArenaInfo(enemyAvatarState, characterSheet, costumeStatSheet, true); listCheck = true; rawEnemyInfo = (Dictionary)enemyInfo.Serialize(); } else { enemyInfo = new ArenaInfo(rawEnemyInfo); } if (arenaInfo.DailyChallengeCount <= 0) { throw new NotEnoughWeeklyArenaChallengeCountException( addressesHex + NotEnoughWeeklyArenaChallengeCountException.BaseMessage); } ArenaInfo = new ArenaInfo(rawArenaInfo); EnemyArenaInfo = new ArenaInfo(rawEnemyInfo); var rankingSheets = sheets.GetRankingSimulatorSheets(); var player = new Player(avatarState, rankingSheets); var enemyPlayerDigest = new EnemyPlayerDigest(enemyAvatarState); var simulator = new RankingSimulator( ctx.Random, player, enemyPlayerDigest, new List <Guid>(), rankingSheets, StageId, arenaInfo, enemyInfo, costumeStatSheet); simulator.Simulate(); sw.Stop(); Log.Verbose( "{AddressesHex}RankingBattle Simulate() with equipment:({Equipment}), costume:({Costume}): {Elapsed}", addressesHex, string.Join(",", simulator.Player.Equipments.Select(r => r.ItemId)), string.Join(",", simulator.Player.Costumes.Select(r => r.ItemId)), sw.Elapsed ); Log.Verbose( "{AddressesHex}Execute RankingBattle({AvatarAddress}); result: {Result} event count: {EventCount}", addressesHex, avatarAddress, simulator.Log.result, simulator.Log.Count ); sw.Restart(); foreach (var itemBase in simulator.Reward.OrderBy(i => i.Id)) { Log.Verbose( "{AddressesHex}RankingBattle Add Reward Item({ItemBaseId}): {Elapsed}", addressesHex, itemBase.Id, sw.Elapsed); avatarState.inventory.AddItem(itemBase); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Serialize WeeklyArenaState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); states = states .SetState(inventoryAddress, avatarState.inventory.Serialize()) .SetState(arenaInfoAddress, arenaInfo.Serialize()) .SetState(enemyInfoAddress, enemyInfo.Serialize()) .SetState(questListAddress, avatarState.questList.Serialize()); if (migrationRequired) { states = states .SetState(worldInformationAddress, avatarState.worldInformation.Serialize()) .SetState(avatarAddress, avatarState.SerializeV2()); } if (listCheck) { var addressList = states.TryGetState(addressListAddress, out List rawAddressList) ? rawAddressList.ToList(StateExtensions.ToAddress) : new List <Address>(); if (!addressList.Contains(avatarAddress)) { addressList.Add(avatarAddress); } if (!addressList.Contains(enemyAddress)) { addressList.Add(enemyAddress); } states = states.SetState(addressListAddress, addressList.Aggregate(List.Empty, (current, address) => current.Add(address.Serialize()))); } sw.Stop(); Log.Verbose("{AddressesHex}RankingBattle Serialize AvatarState: {Elapsed}", addressesHex, sw.Elapsed); sw.Restart(); var ended = DateTimeOffset.UtcNow; Log.Verbose("{AddressesHex}RankingBattle Total Executed Time: {Elapsed}", addressesHex, ended - started); EnemyPlayerDigest = enemyPlayerDigest; return(states); } // Run Backward compatible return(BackwardCompatibleExecute(rawWeeklyArenaState, sheets, avatarState, costumeStatSheet, sw, addressesHex, enemyAvatarState, ctx, states, inventoryAddress, questListAddress, migrationRequired, worldInformationAddress, started)); }