package com.alterdekim.hearthhack.component; import com.alterdekim.PegasusGame; import com.alterdekim.PegasusShared; import com.alterdekim.hearthhack.util.GameDeck; import com.alterdekim.hearthhack.component.interfaces.GamePacketCallback; import com.alterdekim.hearthhack.component.interfaces.IGameRoom; import com.alterdekim.hearthhack.config.ObjectConfig; import com.alterdekim.hearthhack.dto.RoomPlayerDTO; import com.alterdekim.hearthhack.entity.Deck; import com.alterdekim.hearthhack.game.*; import com.alterdekim.hearthhack.service.UserService; import com.alterdekim.hearthhack.util.PegasusPacket; import com.google.protobuf.InvalidProtocolBufferException; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.stream.Collectors; import java.util.stream.IntStream; @Slf4j public class GameRoom extends Thread implements IGameRoom { private static final List bnets = List.of(PegasusShared.BnetId.newBuilder() .setHi(144115198130930503L) .setLo(78330215).build(), PegasusShared.BnetId.newBuilder() .setHi(144115198130930503L) .setLo(77500085).build()); private final ObjectConfig objectConfig; @Getter private final List players; private final ConcurrentHashMap decks; private final ConcurrentHashMap callbacks; private final UserService userService; @Getter private final String password; private GameState globalState; private RunningState runningState; @Getter private final ConcurrentLinkedQueue incomeQueue; private final ConcurrentLinkedQueue outcomeQueue; // TODO: abolish that later. It's a temporary solution private int entity_id = 4; public GameRoom(List players, UserService userService, String password, ObjectConfig objectConfig) { this.players = players; this.userService = userService; this.password = password; this.incomeQueue = new ConcurrentLinkedQueue<>(); this.outcomeQueue = new ConcurrentLinkedQueue<>(); this.decks = new ConcurrentHashMap<>(); this.callbacks = new ConcurrentHashMap<>(); this.globalState = GameState.CreateGame; this.runningState = RunningState.INITIAL_DEAL; this.objectConfig = objectConfig; log.info("GameRoom players: {}", this.players); this.start(); // TODO: debug mode should stop that } private void processIncomePackets() { if( this.incomeQueue.isEmpty() ) return; IncomeGamePacket packet = this.incomeQueue.peek(); if( findPlayerById(packet.getPlayerId()).isEmpty() ) return; processIncomePacket(packet); this.incomeQueue.poll(); } private void processOutcomePackets() { if( this.outcomeQueue.isEmpty() ) return; OutcomeGamePacket packet = this.outcomeQueue.peek(); GamePacketCallback callback = this.callbacks.get(packet.getPlayerId()); if (callback == null) return; callback.onMessage(packet.getPacket()); this.outcomeQueue.poll(); } private void processIncomePacket(IncomeGamePacket packet) { try { switch (PegasusPacketType.fromInt(packet.getPacket().getType())) { case SendChoices -> processChoices(packet.getPlayerId(), PegasusGame.ChooseEntities.parseFrom((byte[]) packet.getPacket().getBody())); case SendEmoteOrUI -> processEmoteOrUI(packet.getPlayerId(), PegasusGame.UserUI.parseFrom((byte[]) packet.getPacket().getBody())); default -> log.warn("processIncomePacket: {}", packet.getPacket()); } } catch (InvalidProtocolBufferException e) { log.error(e.getMessage()); } } private void processChoices(final Long id, PegasusGame.ChooseEntities packet) { if(this.globalState != GameState.Running || this.runningState != RunningState.INITIAL_DEAL || this.findPlayerById(id).isEmpty()) return; // initial_deal state: List redeal = this.decks.get(id).getHandCards() .stream() .map(PegasusGame.PowerHistoryEntity.Builder::getEntity) .filter(entity -> !packet.getEntitiesList().contains(entity)) .collect(Collectors.toList()); PegasusGame.PowerHistory.Builder pw = PegasusGame.PowerHistory.newBuilder(); pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setTagChange(PegasusGame.PowerHistoryTagChange.newBuilder() .setEntity(this.findPlayerById(id).get().getController()+1) .setTag(GameTag.MULLIGAN_STATE.getValue()) .setValue(TagMulligan.DEALING.ordinal()) ) ); Queue handPoses = new ArrayDeque<>(); IntStream.range(0, this.decks.get(id).getSize()) .boxed() .filter(c -> redeal.contains(this.decks.get(id).getCard(c).getEntity())) .forEach(i -> { PegasusGame.PowerHistoryEntity.Builder b = this.decks.get(id).getCard(i) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE.getValue()) .setValue(TagZone.DECK.ordinal()) ); handPoses.add( b.getTagsList() .stream() .filter(t -> t.getName() == GameTag.ZONE_POSITION.getValue()) .map(PegasusGame.Tag::getValue) .findFirst() .orElse(0) ); pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setTagChange(PegasusGame.PowerHistoryTagChange.newBuilder() .setEntity(this.decks.get(id).getCard(i).getEntity()) .setTag(GameTag.ZONE.getValue()) .setValue(TagZone.DECK.ordinal()) ) ); this.decks.get(id).updateCard(b, i); }); new Random() .ints(handPoses.size(), 0, this.decks.get(id).getSize()) .boxed() .forEach(i -> { var l = this.decks.get(id).getCard(i); IntStream.range(0, l.getTagsCount()) .boxed() .filter(h -> l.getTags(h).getName() == GameTag.ZONE_POSITION.getValue()) .forEach(l::removeTags); PegasusGame.Tag t = PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE_POSITION.getValue()) .setValue(handPoses.poll()) .build(); l.addTags(t); pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setTagChange(PegasusGame.PowerHistoryTagChange.newBuilder() .setEntity(l.getEntity()) .setTag(GameTag.ZONE_POSITION.getValue()) .setValue(t.getValue()) ) ); pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setTagChange(PegasusGame.PowerHistoryTagChange.newBuilder() .setEntity(l.getEntity()) .setTag(GameTag.ZONE.getValue()) .setValue(TagZone.HAND.ordinal()) ) ); IntStream.range(0, l.getTagsCount()) .boxed() .filter(h -> l.getTags(h).getName() == GameTag.ZONE.getValue()) .forEach(h -> l.setTags(h, l.getTags(h).toBuilder().setValue(TagZone.HAND.ordinal()))); this.decks.get(id).updateCard(l, i); }); pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setTagChange(PegasusGame.PowerHistoryTagChange.newBuilder() .setEntity(this.findPlayerById(id).get().getController()+1) .setTag(GameTag.MULLIGAN_STATE.getValue()) .setValue(TagMulligan.WAITING.ordinal()) ) ); pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setTagChange(PegasusGame.PowerHistoryTagChange.newBuilder() .setEntity(this.findPlayerById(id).get().getController()+1) .setTag(GameTag.MULLIGAN_STATE.getValue()) .setValue(TagMulligan.DONE.ordinal()) ) ); pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setTagChange(PegasusGame.PowerHistoryTagChange.newBuilder() .setEntity(1) .setTag(GameTag.NEXT_STEP.getValue()) .setValue(TagStep.MAIN_READY.ordinal()) ) ); this.broadcast(new PegasusPacket(19, 0, pw.build().toByteArray())); // log.info("Initial_deal choices: player_id={}; packet={}", id, packet); } private void processEmoteOrUI(final Long id, PegasusGame.UserUI packet) { this.players.stream() .filter(p -> p.getUserId().longValue() != id.longValue()) .forEach(p -> this.outcomeQueue.add( new OutcomeGamePacket( p.getUserId(), new PegasusPacket( 15, 0, packet.toBuilder().setPlayerId(id.intValue()).build().toByteArray()) ) ) ); } private void updateGameState() { // giant switch switch (this.globalState) { case CreateGame -> createGameEntity(); case CreateDecks -> createDeckEntities(); case CreateHeroes -> createPlayerHeroEntity(); } } public void updateCallback(Long playerId, GamePacketCallback callback) { this.callbacks.put(playerId, callback); } @Override public void run() { while(true) { processIncomePackets(); updateGameState(); processOutcomePackets(); } } @Override public void createGameEntity() { log.info("create Game Entity"); PegasusGame.PowerHistory powerHistory = PegasusGame.PowerHistory.newBuilder() .addList(PegasusGame.PowerHistoryData.newBuilder() .setCreateGame(PegasusGame.PowerHistoryCreateGame.newBuilder() .setGameEntity(PegasusGame.Entity.newBuilder() .setId(1) .addTags(PegasusGame.Tag.newBuilder() .setName(10) .setValue(85) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.CARDTYPE.getValue()) .setValue(TagCardType.GAME.ordinal()) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.TURN.getValue()) .setValue(1) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.STATE.getValue()) .setValue(TagState.RUNNING.ordinal()) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE.getValue()) .setValue(TagZone.PLAY.ordinal()) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ENTITY_ID.getValue()) .setValue(1) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.STEP.getValue()) .setValue(TagStep.BEGIN_MULLIGAN.ordinal()) // 10 ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.NEXT_STEP.getValue()) .setValue(TagStep.BEGIN_MULLIGAN.ordinal()) // 12 ) ) .addAllPlayers(createPlayersEntity()) ) ).build(); this.broadcast(new PegasusPacket(19, 0, powerHistory.toByteArray())); this.nextGlobalState(); } public List createPlayersEntity() { log.info("create Players entities"); List pls = new ArrayList<>(); for( int i = 2, pi = 0; i < 4; i++, pi++ ) { final PegasusGame.Entity.Builder entity = PegasusGame.Entity.newBuilder().setId(i == 2 ? 3 : 2); if( pi < this.players.size() ) { players.get(pi).setController(i == 2 ? 2 : 1); GameDeck gd = new GameDeck(); userService.getDeckContentForDeckId(players.get(pi).getUserId(), players.get(pi).getDeckId()) .stream() .map(d -> card2Entity(d.getAssetId()).get()) .forEach(gd::addCard); decks.put(players.get(pi).getUserId(), gd); } if( i == 2 ) { entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.FIRST_PLAYER.getValue()) .setValue(1) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.CURRENT_PLAYER.getValue()) .setValue(1) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.RESOURCES.getValue()) .setValue(1) ); } entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.HERO_ENTITY.getValue()) .setValue(i == 2 ? 66 : 64) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.PLAYSTATE.getValue()) .setValue(TagPlayState.PLAYING.ordinal()) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.TEAM_ID.getValue()) .setValue(i == 2 ? 2 : 1) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.PLAYER_ID.getValue()) .setValue(i == 2 ? 2 : 1) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.MAXHANDSIZE.getValue()) .setValue(10) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.STARTHANDSIZE.getValue()) .setValue(4) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.NUM_TURNS_LEFT.getValue()) .setValue(1) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.CARDTYPE.getValue()) .setValue(TagCardType.PLAYER.ordinal()) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE.getValue()) .setValue(TagZone.PLAY.ordinal()) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.TIMEOUT.getValue()) .setValue(75) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.MAXRESOURCES.getValue()) .setValue(10) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ENTITY_ID.getValue()) .setValue(i == 2 ? 3 : 2) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.CONTROLLER.getValue()) .setValue(i == 2 ? 2 : 1) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.MULLIGAN_STATE.getValue()) .setValue(TagMulligan.INPUT.ordinal()) ); entity.addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.NUM_CARDS_DRAWN_THIS_TURN.getValue()) .setValue(i == 2 ? 1 : 4) ); // TODO: make custom cardback selection pls.add( PegasusGame.Player.newBuilder() .setId(i) .setGameAccountId(bnets.get(i-2)) .setCardBack(pi < this.players.size() ? userService.getCardBackById(players.get(pi).getUserId()).getBackId() : 0) .setEntity(entity) .build() ); } return pls; } @Override public void createDeckEntities() { log.info("create Deck Entities"); // sugar for debug with 1 player. Must be erased after debug. PegasusGame.PowerHistory.Builder pw = PegasusGame.PowerHistory.newBuilder(); for(int i = 0; i < 26; i++, this.entity_id++) { pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setFullEntity(PegasusGame.PowerHistoryEntity.newBuilder() .setEntity(this.entity_id) .setName("") .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ENTITY_ID.getValue()) .setValue(this.entity_id) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.CONTROLLER.getValue()) .setValue(1) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE.getValue()) .setValue(TagZone.DECK.ordinal()) ) ) ); } for(int i = 1; i <= 5; i++, this.entity_id++) { pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setFullEntity(PegasusGame.PowerHistoryEntity.newBuilder() .setEntity(this.entity_id) .setName("") .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ENTITY_ID.getValue()) .setValue(this.entity_id) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.CONTROLLER.getValue()) .setValue(1) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE_POSITION.getValue()) .setValue(i) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE.getValue()) .setValue(TagZone.HAND.ordinal()) ) ) ); } List ens = List.of( card2Entity("TB_SPT_Boss").get(), card2Entity("CS1h_001").get() ); //this.hero_p1 = this.entity_id; for(int i = 0; i < 2; i++, this.entity_id++) { pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setFullEntity(ens.get(i) .setEntity(this.entity_id) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ENTITY_ID.getValue()) .setValue(this.entity_id) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.CONTROLLER.getValue()) .setValue(1) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE.getValue()) .setValue(TagZone.PLAY.ordinal()) ) ) ); } // other player for( RoomPlayerDTO player : this.players ) { int di = 0; for (int i = 0; i < 26; i++, this.entity_id++, di++) { PegasusGame.PowerHistoryEntity.Builder b = di < this.decks.get(player.getUserId()).getSize() ? this.decks.get(player.getUserId()).getCard(di) : PegasusGame.PowerHistoryEntity.newBuilder(); log.info("bBuilder: {}", b.getName()); pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setFullEntity(b .setEntity(this.entity_id) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ENTITY_ID.getValue()) .setValue(this.entity_id) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.CONTROLLER.getValue()) .setValue(player.getController()) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE.getValue()) .setValue(TagZone.DECK.ordinal()) ) ) ); this.decks.get(player.getUserId()).updateCard(b, di); } for (int i = 1; i <= 3; i++, this.entity_id++, di++) { PegasusGame.PowerHistoryEntity.Builder b = di < this.decks.get(player.getUserId()).getSize() ? this.decks.get(player.getUserId()).getCard(di) : PegasusGame.PowerHistoryEntity.newBuilder(); log.info("HAND: {}; {}; {}; {}", b, di < this.decks.get(player.getUserId()).getSize(), di, this.decks.get(player.getUserId()).getSize()); pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setFullEntity(b .setEntity(this.entity_id) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ENTITY_ID.getValue()) .setValue(this.entity_id) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.CONTROLLER.getValue()) .setValue(player.getController()) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE_POSITION.getValue()) .setValue(i) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE.getValue()) .setValue(TagZone.HAND.ordinal()) ) ) ); this.decks.get(player.getUserId()).updateCard(b, di); } // there was a place for hero & hero_power pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setFullEntity(card2Entity("CS2_103e2").get() .setEntity(this.entity_id) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ENTITY_ID.getValue()) .setValue(this.entity_id) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.CONTROLLER.getValue()) .setValue(player.getController()) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE.getValue()) .setValue(TagZone.SETASIDE.ordinal()) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE_POSITION.getValue()) .setValue(0) ) ) ); this.entity_id++; } this.broadcast(new PegasusPacket(19, 0, pw.build().toByteArray())); this.nextGlobalState(); } @Override public void createPlayerHeroEntity() { log.info("Player hero entity"); PegasusGame.PowerHistory.Builder pw = PegasusGame.PowerHistory.newBuilder(); for(RoomPlayerDTO player : players) { Optional deck = userService.getDecksForUser(player.getUserId()) .stream() .filter(d -> d.getId().longValue() == player.getDeckId().longValue()) .findFirst(); pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setFullEntity(card2Entity(deck.get().getHero().longValue()).get() .setEntity(this.entity_id) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ENTITY_ID.getValue()) .setValue(this.entity_id) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.CONTROLLER.getValue()) .setValue(player.getController()) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE.getValue()) .setValue(TagZone.PLAY.ordinal()) ) ) ); //this.hero_p2 = this.entity_id; this.entity_id++; pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setFullEntity(getHeroPowerFromHeroId(deck.get().getHero().longValue()).get() .setEntity(this.entity_id) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ENTITY_ID.getValue()) .setValue(this.entity_id) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.CONTROLLER.getValue()) .setValue(player.getController()) ) .addTags(PegasusGame.Tag.newBuilder() .setName(GameTag.ZONE.getValue()) .setValue(TagZone.PLAY.ordinal()) ) ) ); } pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setTagChange(PegasusGame.PowerHistoryTagChange.newBuilder() .setEntity(2) .setTag(GameTag.MULLIGAN_STATE.getValue()) .setValue(TagMulligan.INPUT.ordinal()) ) ); pw.addList(PegasusGame.PowerHistoryData.newBuilder() .setTagChange(PegasusGame.PowerHistoryTagChange.newBuilder() .setEntity(3) .setTag(GameTag.MULLIGAN_STATE.getValue()) .setValue(TagMulligan.INPUT.ordinal()) ) ); PegasusGame.EntityChoices entityChoices = PegasusGame.EntityChoices.newBuilder() .setId(1) .setChoiceType(1) .setCountMin(0) .setCountMax(3) .addAllEntities(decks.get(players.get(0).getUserId()) .getHandCards() .stream() .map(PegasusGame.PowerHistoryEntity.Builder::getEntity) .collect(Collectors.toList()) ) .setSource(1) .setPlayerId(2) .build(); this.broadcast(new PegasusPacket( 17, 0, entityChoices.toByteArray())); this.broadcast(new PegasusPacket(19, 0, pw.build().toByteArray())); this.entity_id++; /* PegasusGame.AllOptions allOptions = PegasusGame.AllOptions.newBuilder() .setId(1) .addOptions(PegasusGame.Option.newBuilder() .setType(END_TURN) ) .addOptions(PegasusGame.Option.newBuilder() .setType(PegasusGame.Option.Type.POWER) .setMainOption(PegasusGame.SubOption.newBuilder() .setId(this.hero_p2) .addTargets(this.hero_p1) ) ) .build(); this.broadcast(new PegasusPacket( 14, 0, allOptions.toByteArray()));*/ this.nextGlobalState(); } private Optional findPlayerById(Long id) { return players.stream().filter(p -> p.getUserId().longValue() == id.longValue()).findFirst(); } private void broadcast(PegasusPacket packet) { this.players.forEach(p -> this.outcomeQueue.add(new OutcomeGamePacket(p.getUserId(), packet))); } private void nextGlobalState() { this.globalState = GameState.next(this.globalState); } private Optional card2Entity(String cardId) { return this.objectConfig.getFormattedCards() .getObjects() .stream() .filter(c -> c.getEntity().getCardId().equals(cardId)) .map(c -> PegasusGame.PowerHistoryEntity.newBuilder() .setName(c.getEntity().getCardId()) .addAllTags(c.getEntity().getTags().stream() .filter(t -> !t.getType().equals("String")) .map(t -> PegasusGame.Tag.newBuilder() .setName(t.getEnumID()) .setValue(t.getValue()) .build() ) .collect(Collectors.toList())) ) .findFirst(); } private Optional card2Entity(Long cardId) { return this.objectConfig.getFormattedCards() .getObjects() .stream() .filter(o -> o.getDbfCard().findField("ID").isPresent() && Long.parseLong(o.getDbfCard().findField("ID").get().getVal()) == cardId) .map(c -> PegasusGame.PowerHistoryEntity.newBuilder() .setName(c.getEntity().getCardId()) .addAllTags(c.getEntity().getTags().stream() .filter(t -> !t.getType().equals("String")) .map(t -> PegasusGame.Tag.newBuilder() .setName(t.getEnumID()) .setValue(t.getValue()) .build() ) .collect(Collectors.toList())) ) .findFirst(); } private Optional getHeroPowerFromHeroId(Long cardId) { return card2Entity(Long.parseLong(this.objectConfig.getFormattedCards() .getObjects() .stream() .filter(o -> o.getDbfCard().findField("ID").isPresent() && Long.parseLong(o.getDbfCard().findField("ID").get().getVal()) == cardId) .findFirst() .get() .getDbfCard() .findField("HERO_POWER_ID") .get() .getVal())); } }