public IAccountStateDelta ResetChallengeCount(IActionContext ctx, IAccountStateDelta states) { var gameConfigState = states.GetGameConfigState(); var index = Math.Max((int)ctx.BlockIndex / gameConfigState.WeeklyArenaInterval, 0); var weeklyAddress = WeeklyArenaState.DeriveAddress(index); var rawWeekly = (Dictionary)states.GetState(weeklyAddress); var resetIndex = rawWeekly["resetIndex"].ToLong(); if (ctx.BlockIndex - resetIndex >= gameConfigState.DailyArenaInterval) { var weekly = new WeeklyArenaState(rawWeekly); if (resetIndex >= RankingBattle.UpdateTargetBlockIndex) { // Reset count each ArenaInfo. weekly.ResetIndex = ctx.BlockIndex; var listAddress = weeklyAddress.Derive("address_list"); if (states.TryGetState(listAddress, out List rawList)) { var addressList = rawList.ToList(StateExtensions.ToAddress); foreach (var address in addressList) { var infoAddress = weeklyAddress.Derive(address.ToByteArray()); if (states.TryGetState(infoAddress, out Dictionary rawInfo)) { var info = new ArenaInfo(rawInfo); info.ResetCount(); states = states.SetState(infoAddress, info.Serialize()); } } } } else { // Run legacy ResetCount. weekly.ResetCount(ctx.BlockIndex); } states = states.SetState(weeklyAddress, weekly.Serialize()); } 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 IAccountStateDelta PrepareNextArena(IActionContext ctx, IAccountStateDelta states) { var gameConfigState = states.GetGameConfigState(); var index = Math.Max((int)ctx.BlockIndex / gameConfigState.WeeklyArenaInterval, 0); var weeklyAddress = WeeklyArenaState.DeriveAddress(index); var rawWeekly = (Dictionary)states.GetState(weeklyAddress); var nextIndex = index + 1; var nextWeekly = states.GetWeeklyArenaState(nextIndex); if (nextWeekly is null) { nextWeekly = new WeeklyArenaState(nextIndex); states = states.SetState(nextWeekly.address, nextWeekly.Serialize()); } // Beginning block of a new weekly arena. if (ctx.BlockIndex % gameConfigState.WeeklyArenaInterval == 0 && index > 0) { var prevWeeklyAddress = WeeklyArenaState.DeriveAddress(index - 1); var rawPrevWeekly = (Dictionary)states.GetState(prevWeeklyAddress); if (!rawPrevWeekly["ended"].ToBoolean()) { rawPrevWeekly = rawPrevWeekly.SetItem("ended", true.Serialize()); var weekly = new WeeklyArenaState(rawWeekly); var prevWeekly = new WeeklyArenaState(rawPrevWeekly); var listAddress = weekly.address.Derive("address_list"); // Set ArenaInfo, address list for new RankingBattle. var addressList = states.TryGetState(listAddress, out List rawList) ? rawList.ToList(StateExtensions.ToAddress) : new List <Address>(); if (ctx.BlockIndex >= RankingBattle.UpdateTargetBlockIndex) { weekly.ResetIndex = ctx.BlockIndex; // Copy Map to address list. if (ctx.BlockIndex == RankingBattle.UpdateTargetBlockIndex) { foreach (var kv in prevWeekly.Map) { var address = kv.Key; var lazyInfo = kv.Value; var info = new ArenaInfo(lazyInfo.State); states = states.SetState( weeklyAddress.Derive(address.ToByteArray()), info.Serialize()); if (!addressList.Contains(address)) { addressList.Add(address); } } } else { // Copy addresses from prev weekly address list. var prevListAddress = prevWeekly.address.Derive("address_list"); if (states.TryGetState(prevListAddress, out List prevRawList)) { var prevList = prevRawList.ToList(StateExtensions.ToAddress); foreach (var address in prevList.Where(address => !addressList.Contains(address))) { addressList.Add(address); } } // Copy ArenaInfo from prev ArenaInfo. foreach (var address in addressList) { if (states.TryGetState( prevWeekly.address.Derive(address.ToByteArray()), out Dictionary rawInfo)) { var prevInfo = new ArenaInfo(rawInfo); var info = new ArenaInfo(prevInfo); states = states.SetState( weeklyAddress.Derive(address.ToByteArray()), info.Serialize()); } } } // Set address list. states = states.SetState(listAddress, addressList.Aggregate(List.Empty, (current, address) => current.Add(address.Serialize()))); } // Run legacy Update. else { weekly.Update(prevWeekly, ctx.BlockIndex); } states = states.SetState(prevWeeklyAddress, rawPrevWeekly); states = states.SetState(weeklyAddress, weekly.Serialize()); } } 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(); 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)); }