public void TagChange(IHsGameState gameState, string rawTag, int id, string rawValue, IGame game, bool isCreationTag = false) { var tag = LogReaderHelper.ParseEnum <GameTag>(rawTag); var value = LogReaderHelper.ParseTag(tag, rawValue); TagChange(gameState, tag, id, value, game, isCreationTag); }
public void Handle(string logLine, IHsGameState gameState, IGame game) { var creationTag = false; if (GameEntityRegex.IsMatch(logLine)) { var match = GameEntityRegex.Match(logLine); var id = int.Parse(match.Groups["id"].Value); if (!game.Entities.ContainsKey(id)) { game.Entities.Add(id, new Entity(id) { Name = "GameEntity" }); } gameState.SetCurrentEntity(id); if (gameState.DeterminedPlayers) { _tagChangeHandler.InvokeQueuedActions(game); } return; } else if (PlayerEntityRegex.IsMatch(logLine)) { var match = PlayerEntityRegex.Match(logLine); var id = int.Parse(match.Groups["id"].Value); if (!game.Entities.ContainsKey(id)) { game.Entities.Add(id, new Entity(id)); } if (gameState.WasInProgress) { game.Entities[id].Name = game.GetStoredPlayerName(id); } gameState.SetCurrentEntity(id); if (gameState.DeterminedPlayers) { _tagChangeHandler.InvokeQueuedActions(game); } return; } else if (TagChangeRegex.IsMatch(logLine)) { var match = TagChangeRegex.Match(logLine); var rawEntity = match.Groups["entity"].Value.Replace("UNKNOWN ENTITY ", ""); int entityId; if (rawEntity.StartsWith("[") && EntityRegex.IsMatch(rawEntity)) { var entity = EntityRegex.Match(rawEntity); var id = int.Parse(entity.Groups["id"].Value); _tagChangeHandler.TagChange(gameState, match.Groups["tag"].Value, id, match.Groups["value"].Value, game); } else if (int.TryParse(rawEntity, out entityId)) { _tagChangeHandler.TagChange(gameState, match.Groups["tag"].Value, entityId, match.Groups["value"].Value, game); } else { var entity = game.Entities.FirstOrDefault(x => x.Value.Name == rawEntity); if (entity.Value == null) { var players = game.Entities.Where(x => x.Value.HasTag(GameTag.PLAYER_ID)).Take(2).ToList(); var unnamedPlayers = players.Where(x => string.IsNullOrEmpty(x.Value.Name)).ToList(); var unknownHumanPlayer = players.FirstOrDefault(x => x.Value.Name == "UNKNOWN HUMAN PLAYER"); if (unnamedPlayers.Count == 0 && unknownHumanPlayer.Value != null) { Log.Info("Updating UNKNOWN HUMAN PLAYER"); entity = unknownHumanPlayer; } //while the id is unknown, store in tmp entities var tmpEntity = _tmpEntities.FirstOrDefault(x => x.Name == rawEntity); if (tmpEntity == null) { tmpEntity = new Entity(_tmpEntities.Count + 1) { Name = rawEntity }; _tmpEntities.Add(tmpEntity); } GameTag tag; Enum.TryParse(match.Groups["tag"].Value, out tag); var value = LogReaderHelper.ParseTag(tag, match.Groups["value"].Value); if (unnamedPlayers.Count == 1) { entity = unnamedPlayers.Single(); } else if (unnamedPlayers.Count == 2 && tag == GameTag.CURRENT_PLAYER && value == 0) { entity = game.Entities.FirstOrDefault(x => x.Value?.HasTag(GameTag.CURRENT_PLAYER) ?? false); } if (entity.Value != null) { entity.Value.Name = tmpEntity.Name; foreach (var t in tmpEntity.Tags) { _tagChangeHandler.TagChange(gameState, t.Key, entity.Key, t.Value, game); } _tmpEntities.Remove(tmpEntity); _tagChangeHandler.TagChange(gameState, match.Groups["tag"].Value, entity.Key, match.Groups["value"].Value, game); } if (_tmpEntities.Contains(tmpEntity)) { tmpEntity.SetTag(tag, value); var player = game.Player.Name == tmpEntity.Name ? game.Player : (game.Opponent.Name == tmpEntity.Name ? game.Opponent : null); if (player != null) { var playerEntity = game.Entities.FirstOrDefault(x => x.Value.GetTag(GameTag.PLAYER_ID) == player.Id).Value; if (playerEntity != null) { playerEntity.Name = tmpEntity.Name; foreach (var t in tmpEntity.Tags) { _tagChangeHandler.TagChange(gameState, t.Key, playerEntity.Id, t.Value, game); } _tmpEntities.Remove(tmpEntity); } } } } else { _tagChangeHandler.TagChange(gameState, match.Groups["tag"].Value, entity.Key, match.Groups["value"].Value, game); } } } else if (CreationRegex.IsMatch(logLine)) { var match = CreationRegex.Match(logLine); var id = int.Parse(match.Groups["id"].Value); var cardId = match.Groups["cardId"].Value; if (!game.Entities.ContainsKey(id)) { if (string.IsNullOrEmpty(cardId)) { if (gameState.KnownCardIds.TryGetValue(id, out cardId)) { Log.Info($"Found known cardId for entity {id}: {cardId}"); gameState.KnownCardIds.Remove(id); } } game.Entities.Add(id, new Entity(id) { CardId = cardId }); } gameState.SetCurrentEntity(id); if (gameState.DeterminedPlayers) { _tagChangeHandler.InvokeQueuedActions(game); } gameState.CurrentEntityHasCardId = !string.IsNullOrEmpty(cardId); gameState.CurrentEntityZone = LogReaderHelper.ParseEnum <Zone>(match.Groups["zone"].Value); return; } else if (UpdatingEntityRegex.IsMatch(logLine)) { var match = UpdatingEntityRegex.Match(logLine); var cardId = match.Groups["cardId"].Value; var rawEntity = match.Groups["entity"].Value; int entityId; if (rawEntity.StartsWith("[") && EntityRegex.IsMatch(rawEntity)) { var entity = EntityRegex.Match(rawEntity); entityId = int.Parse(entity.Groups["id"].Value); } else if (!int.TryParse(rawEntity, out entityId)) { entityId = -1; } if (entityId != -1) { if (!game.Entities.ContainsKey(entityId)) { game.Entities.Add(entityId, new Entity(entityId)); } game.Entities[entityId].CardId = cardId; gameState.SetCurrentEntity(entityId); if (gameState.DeterminedPlayers) { _tagChangeHandler.InvokeQueuedActions(game); } } if (gameState.JoustReveals > 0) { Entity currentEntity; if (game.Entities.TryGetValue(entityId, out currentEntity)) { if (currentEntity.IsControlledBy(game.Opponent.Id)) { gameState.GameHandler.HandleOpponentJoust(currentEntity, cardId, gameState.GetTurnNumber()); } else if (currentEntity.IsControlledBy(game.Player.Id)) { gameState.GameHandler.HandlePlayerJoust(currentEntity, cardId, gameState.GetTurnNumber()); } } //gameState.JoustReveals--; } return; } else if (CreationTagRegex.IsMatch(logLine) && !logLine.Contains("HIDE_ENTITY")) { var match = CreationTagRegex.Match(logLine); _tagChangeHandler.TagChange(gameState, match.Groups["tag"].Value, gameState.CurrentEntityId, match.Groups["value"].Value, game, true); creationTag = true; } if (logLine.Contains("End Spectator")) { gameState.GameHandler.HandleGameEnd(); } else if (BlockStartRegex.IsMatch(logLine)) { var playerEntity = game.Entities.FirstOrDefault( e => e.Value.HasTag(GameTag.PLAYER_ID) && e.Value.GetTag(GameTag.PLAYER_ID) == game.Player.Id); var opponentEntity = game.Entities.FirstOrDefault( e => e.Value.HasTag(GameTag.PLAYER_ID) && e.Value.GetTag(GameTag.PLAYER_ID) == game.Opponent.Id); var match = BlockStartRegex.Match(logLine); var actionStartingCardId = match.Groups["cardId"].Value.Trim(); var actionStartingEntityId = int.Parse(match.Groups["id"].Value); if (string.IsNullOrEmpty(actionStartingCardId)) { Entity actionEntity; if (game.Entities.TryGetValue(actionStartingEntityId, out actionEntity)) { actionStartingCardId = actionEntity.CardId; } } if (string.IsNullOrEmpty(actionStartingCardId)) { return; } if (match.Groups["type"].Value == "TRIGGER") { switch (actionStartingCardId) { case Collectible.Rogue.TradePrinceGallywix: AddKnownCardId(gameState, game, game.Entities[gameState.LastCardPlayed].CardId); AddKnownCardId(gameState, game, NonCollectible.Neutral.TradePrinceGallywix_GallywixsCoinToken); break; } } else //POWER { switch (actionStartingCardId) { case Collectible.Rogue.GangUp: AddTargetAsKnownCardId(gameState, game, match, 3); break; case Collectible.Rogue.BeneathTheGrounds: AddKnownCardId(gameState, game, NonCollectible.Rogue.BeneaththeGrounds_AmbushToken, 3); break; case Collectible.Warrior.IronJuggernaut: AddKnownCardId(gameState, game, NonCollectible.Warrior.IronJuggernaut_BurrowingMineToken); break; case Collectible.Druid.Recycle: AddTargetAsKnownCardId(gameState, game, match); break; case Collectible.Mage.ForgottenTorch: AddKnownCardId(gameState, game, NonCollectible.Mage.ForgottenTorch_RoaringTorchToken); break; case Collectible.Warlock.CurseOfRafaam: AddKnownCardId(gameState, game, NonCollectible.Warlock.CurseofRafaam_CursedToken); break; case Collectible.Neutral.AncientShade: AddKnownCardId(gameState, game, NonCollectible.Neutral.AncientShade_AncientCurseToken); break; case Collectible.Priest.ExcavatedEvil: AddKnownCardId(gameState, game, Collectible.Priest.ExcavatedEvil); break; case Collectible.Neutral.EliseStarseeker: AddKnownCardId(gameState, game, NonCollectible.Neutral.EliseStarseeker_MapToTheGoldenMonkeyToken); break; case NonCollectible.Neutral.EliseStarseeker_MapToTheGoldenMonkeyToken: AddKnownCardId(gameState, game, NonCollectible.Neutral.EliseStarseeker_GoldenMonkeyToken); break; case Collectible.Neutral.Doomcaller: AddKnownCardId(gameState, game, NonCollectible.Neutral.Cthun); break; default: if (playerEntity.Value != null && playerEntity.Value.GetTag(GameTag.CURRENT_PLAYER) == 1 && !gameState.PlayerUsedHeroPower || opponentEntity.Value != null && opponentEntity.Value.GetTag(GameTag.CURRENT_PLAYER) == 1 && !gameState.OpponentUsedHeroPower) { var card = Database.GetCardFromId(actionStartingCardId); if (card.Type == "Hero Power") { if (playerEntity.Value != null && playerEntity.Value.GetTag(GameTag.CURRENT_PLAYER) == 1) { gameState.GameHandler.HandlePlayerHeroPower(actionStartingCardId, gameState.GetTurnNumber()); gameState.PlayerUsedHeroPower = true; } else if (opponentEntity.Value != null) { gameState.GameHandler.HandleOpponentHeroPower(actionStartingCardId, gameState.GetTurnNumber()); gameState.OpponentUsedHeroPower = true; } } } break; } } } else if (logLine.Contains("BlockType=JOUST")) { gameState.JoustReveals = 2; } else if (logLine.Contains("CREATE_GAME")) { _tagChangeHandler.ClearQueuedActions(); } else if (gameState.GameTriggerCount == 0 && logLine.Contains("BLOCK_START BlockType=TRIGGER Entity=GameEntity")) { gameState.GameTriggerCount++; } else if (gameState.GameTriggerCount < 10 && logLine.Contains("BLOCK_END") && (game.GameEntity?.HasTag(GameTag.TURN) ?? false)) { gameState.GameTriggerCount += 10; _tagChangeHandler.InvokeQueuedActions(game); gameState.SetupDone = true; } if (game.IsInMenu) { return; } if (!creationTag && gameState.DeterminedPlayers) { _tagChangeHandler.InvokeQueuedActions(game); } if (!creationTag) { gameState.ResetCurrentEntity(); } }
public void Handle(string logLine, IHsGameState gameState, IGame game) { var setup = false; var creationTag = false; if (GameEntityRegex.IsMatch(logLine)) { var match = GameEntityRegex.Match(logLine); var id = int.Parse(match.Groups["id"].Value); if (!game.Entities.ContainsKey(id)) { game.Entities.Add(id, new Entity(id) { Name = "GameEntity" }); } gameState.CurrentEntityId = id; setup = true; } else if (PlayerEntityRegex.IsMatch(logLine)) { var match = PlayerEntityRegex.Match(logLine); var id = int.Parse(match.Groups["id"].Value); if (!game.Entities.ContainsKey(id)) { game.Entities.Add(id, new Entity(id)); } gameState.CurrentEntityId = id; setup = true; if (gameState.WasInProgress) { game.Entities[id].Name = game.GetStoredPlayerName(id); } } else if (TagChangeRegex.IsMatch(logLine)) { var match = TagChangeRegex.Match(logLine); var rawEntity = match.Groups["entity"].Value.Replace("UNKNOWN ENTITY ", ""); int entityId; if (rawEntity.StartsWith("[") && EntityRegex.IsMatch(rawEntity)) { var entity = EntityRegex.Match(rawEntity); var id = int.Parse(entity.Groups["id"].Value); _tagChangeHandler.TagChange(gameState, match.Groups["tag"].Value, id, match.Groups["value"].Value, game); } else if (int.TryParse(rawEntity, out entityId)) { _tagChangeHandler.TagChange(gameState, match.Groups["tag"].Value, entityId, match.Groups["value"].Value, game); } else { var entity = game.Entities.FirstOrDefault(x => x.Value.Name == rawEntity); if (entity.Value == null) { var players = game.Entities.Where(x => x.Value.HasTag(GAME_TAG.PLAYER_ID)).Take(2).ToList(); var unnamedPlayers = players.Where(x => string.IsNullOrEmpty(x.Value.Name)).ToList(); var unknownHumanPlayer = players.FirstOrDefault(x => x.Value.Name == "UNKNOWN HUMAN PLAYER"); if (unnamedPlayers.Count == 0 && unknownHumanPlayer.Value != null) { Log.Info("Updating UNKNOWN HUMAN PLAYER"); entity = unknownHumanPlayer; SetPlayerName(game, entity.Value.GetTag(GAME_TAG.PLAYER_ID), rawEntity); } //while the id is unknown, store in tmp entities var tmpEntity = _tmpEntities.FirstOrDefault(x => x.Name == rawEntity); if (tmpEntity == null) { tmpEntity = new Entity(_tmpEntities.Count + 1) { Name = rawEntity }; _tmpEntities.Add(tmpEntity); } GAME_TAG tag; Enum.TryParse(match.Groups["tag"].Value, out tag); var value = LogReaderHelper.ParseTag(tag, match.Groups["value"].Value); if (unnamedPlayers.Count == 1) { entity = unnamedPlayers.Single(); } else if (unnamedPlayers.Count == 2 && tag == GAME_TAG.CURRENT_PLAYER && value == 0) { entity = game.Entities.FirstOrDefault(x => x.Value?.HasTag(GAME_TAG.CURRENT_PLAYER) ?? false); } if (entity.Value != null) { entity.Value.Name = tmpEntity.Name; foreach (var t in tmpEntity.Tags) { _tagChangeHandler.TagChange(gameState, t.Key, tmpEntity.GetTag(GAME_TAG.ENTITY_ID), t.Value, game); } SetPlayerName(game, entity.Value.GetTag(GAME_TAG.PLAYER_ID), tmpEntity.Name); _tmpEntities.Remove(tmpEntity); _tagChangeHandler.TagChange(gameState, match.Groups["tag"].Value, entity.Key, match.Groups["value"].Value, game); } if (_tmpEntities.Contains(tmpEntity)) { tmpEntity.SetTag(tag, value); if (tmpEntity.HasTag(GAME_TAG.ENTITY_ID)) { var id = tmpEntity.GetTag(GAME_TAG.ENTITY_ID); if (game.Entities.ContainsKey(id)) { game.Entities[id].Name = tmpEntity.Name; foreach (var t in tmpEntity.Tags) { _tagChangeHandler.TagChange(gameState, t.Key, id, t.Value, game); } _tmpEntities.Remove(tmpEntity); } else { Log.Warn("TMP ENTITY (" + rawEntity + ") NOW HAS A KEY, BUT GAME.ENTITIES DOES NOT CONTAIN THIS KEY"); } } } } else { _tagChangeHandler.TagChange(gameState, match.Groups["tag"].Value, entity.Key, match.Groups["value"].Value, game); } } if (EntityNameRegex.IsMatch(logLine)) { match = EntityNameRegex.Match(logLine); var name = match.Groups["name"].Value; var player = int.Parse(match.Groups["value"].Value); SetPlayerName(game, player, name); } } else if (CreationRegex.IsMatch(logLine)) { var match = CreationRegex.Match(logLine); var id = int.Parse(match.Groups["id"].Value); var cardId = match.Groups["cardId"].Value; if (!game.Entities.ContainsKey(id)) { if (string.IsNullOrEmpty(cardId)) { if (gameState.KnownCardIds.TryGetValue(id, out cardId)) { Log.Info($"Found known cardId for entity {id}: {cardId}"); gameState.KnownCardIds.Remove(id); } } game.Entities.Add(id, new Entity(id) { CardId = cardId }); } gameState.CurrentEntityId = id; gameState.CurrentEntityHasCardId = !string.IsNullOrEmpty(cardId); gameState.CurrentEntityZone = LogReaderHelper.ParseEnum <TAG_ZONE>(match.Groups["zone"].Value); setup = true; } else if (UpdatingEntityRegex.IsMatch(logLine)) { var match = UpdatingEntityRegex.Match(logLine); var cardId = match.Groups["cardId"].Value; var rawEntity = match.Groups["entity"].Value; int entityId; if (rawEntity.StartsWith("[") && EntityRegex.IsMatch(rawEntity)) { var entity = EntityRegex.Match(rawEntity); entityId = int.Parse(entity.Groups["id"].Value); } else if (!int.TryParse(rawEntity, out entityId)) { entityId = -1; } if (entityId != -1) { gameState.CurrentEntityId = entityId; if (!game.Entities.ContainsKey(entityId)) { game.Entities.Add(entityId, new Entity(entityId)); } game.Entities[entityId].CardId = cardId; } if (gameState.JoustReveals > 0) { Entity currentEntity; if (game.Entities.TryGetValue(entityId, out currentEntity)) { if (currentEntity.IsControlledBy(game.Opponent.Id)) { gameState.GameHandler.HandleOpponentJoust(currentEntity, cardId, gameState.GetTurnNumber()); } else if (currentEntity.IsControlledBy(game.Player.Id)) { gameState.GameHandler.HandlePlayerJoust(currentEntity, cardId, gameState.GetTurnNumber()); } } //gameState.JoustReveals--; } } else if (CreationTagRegex.IsMatch(logLine) && !logLine.Contains("HIDE_ENTITY")) { var match = CreationTagRegex.Match(logLine); _tagChangeHandler.TagChange(gameState, match.Groups["tag"].Value, gameState.CurrentEntityId, match.Groups["value"].Value, game, true); setup = true; creationTag = true; } else if ((logLine.Contains("Begin Spectating") || logLine.Contains("Start Spectator")) && game.IsInMenu) { gameState.GameHandler.SetGameMode(GameMode.Spectator); } else if (logLine.Contains("End Spectator")) { gameState.GameHandler.SetGameMode(GameMode.Spectator); gameState.GameHandler.HandleGameEnd(); } else if (ActionStartRegex.IsMatch(logLine)) { var playerEntity = game.Entities.FirstOrDefault(e => e.Value.HasTag(GAME_TAG.PLAYER_ID) && e.Value.GetTag(GAME_TAG.PLAYER_ID) == game.Player.Id); var opponentEntity = game.Entities.FirstOrDefault(e => e.Value.HasTag(GAME_TAG.PLAYER_ID) && e.Value.GetTag(GAME_TAG.PLAYER_ID) == game.Opponent.Id); var match = ActionStartRegex.Match(logLine); var actionStartingCardId = match.Groups["cardId"].Value.Trim(); var actionStartingEntityId = int.Parse(match.Groups["id"].Value); if (string.IsNullOrEmpty(actionStartingCardId)) { Entity actionEntity; if (game.Entities.TryGetValue(actionStartingEntityId, out actionEntity)) { actionStartingCardId = actionEntity.CardId; } } if (string.IsNullOrEmpty(actionStartingCardId)) { return; } if (match.Groups["type"].Value == "TRIGGER") { switch (actionStartingCardId) { case Collectible.Rogue.TradePrinceGallywix: AddKnownCardId(gameState, game, game.Entities[gameState.LastCardPlayed].CardId); AddKnownCardId(gameState, game, NonCollectible.Neutral.GallywixsCoinToken); break; } } else //POWER { switch (actionStartingCardId) { case Collectible.Rogue.GangUp: AddTargetAsKnownCardId(gameState, game, match, 3); break; case Collectible.Rogue.BeneathTheGrounds: AddKnownCardId(gameState, game, NonCollectible.Rogue.AmbushToken, 3); break; case Collectible.Warrior.IronJuggernaut: AddKnownCardId(gameState, game, NonCollectible.Warrior.BurrowingMineToken); break; case Collectible.Druid.Recycle: AddTargetAsKnownCardId(gameState, game, match); break; case Collectible.Mage.ForgottenTorch: AddKnownCardId(gameState, game, NonCollectible.Mage.RoaringTorchToken); break; case Collectible.Warlock.CurseOfRafaam: AddKnownCardId(gameState, game, NonCollectible.Warlock.CursedToken); break; case Collectible.Neutral.AncientShade: AddKnownCardId(gameState, game, NonCollectible.Neutral.AncientCurseToken); break; case Collectible.Priest.ExcavatedEvil: AddKnownCardId(gameState, game, Collectible.Priest.ExcavatedEvil); break; case Collectible.Neutral.EliseStarseeker: AddKnownCardId(gameState, game, NonCollectible.Neutral.MapToTheGoldenMonkeyToken); break; case NonCollectible.Neutral.MapToTheGoldenMonkeyToken: AddKnownCardId(gameState, game, NonCollectible.Neutral.GoldenMonkeyToken); break; default: if (playerEntity.Value != null && playerEntity.Value.GetTag(GAME_TAG.CURRENT_PLAYER) == 1 && !gameState.PlayerUsedHeroPower || opponentEntity.Value != null && opponentEntity.Value.GetTag(GAME_TAG.CURRENT_PLAYER) == 1 && !gameState.OpponentUsedHeroPower) { var card = Database.GetCardFromId(actionStartingCardId); if (card.Type == "Hero Power") { if (playerEntity.Value != null && playerEntity.Value.GetTag(GAME_TAG.CURRENT_PLAYER) == 1) { gameState.GameHandler.HandlePlayerHeroPower(actionStartingCardId, gameState.GetTurnNumber()); gameState.PlayerUsedHeroPower = true; } else if (opponentEntity.Value != null) { gameState.GameHandler.HandleOpponentHeroPower(actionStartingCardId, gameState.GetTurnNumber()); gameState.OpponentUsedHeroPower = true; } } } break; } } } else if (logLine.Contains("BlockType=JOUST")) { gameState.JoustReveals = 2; } else if (logLine.Contains("CREATE_GAME")) { setup = true; _tagChangeHandler.ClearQueuedActions(); } if (!setup) { gameState.SetupDone = true; } if (game.IsInMenu) { return; } if (!creationTag && gameState.DeterminedPlayers) { _tagChangeHandler.InvokeQueuedActions(); } else if (!gameState.DeterminedPlayers && gameState.SetupDone) { Log.Warn("Could not determine players by checking for opponent hand."); var playerCard = game.Entities.FirstOrDefault(x => x.Value.IsInHand && !string.IsNullOrEmpty(x.Value.CardId)).Value; if (playerCard != null) { _tagChangeHandler.DeterminePlayers(gameState, game, playerCard.GetTag(GAME_TAG.CONTROLLER), false); } else { Log.Warn("Could not determine players by checking for player hand either... waiting for draws..."); } } }