Mulligan coding

This commit is contained in:
Michael Wain 2024-08-03 15:58:55 +03:00
parent acf0eb498f
commit 9f9c82474e
7 changed files with 183 additions and 46 deletions

View File

@ -63,7 +63,7 @@ public class GameConnection extends Thread {
this.playerId = (long) handshake.getClientHandle();
return;
}
if( packet.getType() == 115 ) {
if( packet.getType() == PegasusPacketType.SendPing.getValue() ) {
pong();
return;
}

View File

@ -11,15 +11,15 @@ 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.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@Slf4j
@ -46,10 +46,11 @@ public class GameRoom extends Thread implements IGameRoom {
private final String password;
private GameState globalState;
private RunningState runningState;
@Getter
private ConcurrentLinkedQueue<IncomeGamePacket> incomeQueue;
private ConcurrentLinkedQueue<OutcomeGamePacket> outcomeQueue;
private final ConcurrentLinkedQueue<IncomeGamePacket> incomeQueue;
private final ConcurrentLinkedQueue<OutcomeGamePacket> outcomeQueue;
// TODO: abolish that later. It's a temporary solution
private int entity_id = 4;
@ -63,6 +64,7 @@ public class GameRoom extends Thread implements IGameRoom {
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
@ -86,14 +88,137 @@ public class GameRoom extends Thread implements IGameRoom {
}
private void processIncomePacket(IncomeGamePacket packet) {
log.info("processIncomePacket: {}", packet.getPacket());
/* if( packet.getPacket().getType() != 1) return;
List<OutcomeGamePacket> l = this.outcomeQueue.stream()
.filter(p -> p.getPlayerId().longValue() == packet.getPlayerId().longValue())
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<Integer> redeal = this.decks.get(id).getHandCards()
.stream()
.map(PegasusGame.PowerHistoryEntity.Builder::getEntity)
.filter(entity -> !packet.getEntitiesList().contains(entity))
.collect(Collectors.toList());
GamePacketCallback callback = this.callbacks.get(packet.getPlayerId());
if (callback == null) return;
l.forEach(p -> callback.onMessage(p.getPacket()));*/
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<Integer> 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() {
@ -102,7 +227,6 @@ public class GameRoom extends Thread implements IGameRoom {
case CreateGame -> createGameEntity();
case CreateDecks -> createDeckEntities();
case CreateHeroes -> createPlayerHeroEntity();
case CreateHeroPowers -> createPlayerHeroPowerEntity();
}
}
@ -387,7 +511,7 @@ public class GameRoom extends Thread implements IGameRoom {
)
)
);
this.decks.get(player.getUserId()).updateCard(b);
this.decks.get(player.getUserId()).updateCard(b, di);
}
for (int i = 1; i <= 3; i++, this.entity_id++, di++) {
@ -414,7 +538,7 @@ public class GameRoom extends Thread implements IGameRoom {
)
)
);
this.decks.get(player.getUserId()).updateCard(b);
this.decks.get(player.getUserId()).updateCard(b, di);
}
// there was a place for hero & hero_power
@ -449,11 +573,6 @@ public class GameRoom extends Thread implements IGameRoom {
this.nextGlobalState();
}
@Override
public void createCardEntity() {
}
@Override
public void createPlayerHeroEntity() {
log.info("Player hero entity");
@ -562,12 +681,6 @@ public class GameRoom extends Thread implements IGameRoom {
this.nextGlobalState();
}
@Override
public void createPlayerHeroPowerEntity() {
log.info("hero power entity");
this.nextGlobalState();
}
private Optional<RoomPlayerDTO> findPlayerById(Long id) {
return players.stream().filter(p -> p.getUserId().longValue() == id.longValue()).findFirst();
}

View File

@ -3,7 +3,5 @@ package com.alterdekim.hearthhack.component.interfaces;
public interface IGameRoom {
void createGameEntity();
void createDeckEntities();
void createCardEntity();
void createPlayerHeroEntity();
void createPlayerHeroPowerEntity();
}

View File

@ -4,7 +4,6 @@ public enum GameState {
CreateGame,
CreateDecks,
CreateHeroes,
CreateHeroPowers,
Running;
public static GameState next(GameState state) {

View File

@ -0,0 +1,24 @@
package com.alterdekim.hearthhack.game;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum PegasusPacketType {
GetGameState(1),
Concede(11),
SendPing(115),
SendChoices(3),
SendOption(2),
SendEmoteOrUI(15);
private final Integer value;
public static PegasusPacketType fromInt(int i) {
for(PegasusPacketType t : values()) {
if( t.getValue() == i ) return t;
}
return SendPing;
}
}

View File

@ -0,0 +1,7 @@
package com.alterdekim.hearthhack.game;
public enum RunningState {
INITIAL_DEAL,
DRAW,
TURN
}

View File

@ -7,33 +7,33 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
public class GameDeck {
private final Map<String, PegasusGame.PowerHistoryEntity.Builder> deck;
private final List<PegasusGame.PowerHistoryEntity.Builder> deck;
public GameDeck() {
this.deck = new HashMap<>();
this.deck = new ArrayList<>();
}
public PegasusGame.PowerHistoryEntity.Builder getCard(Integer i) {
return this.deck.get(getKeys().get(i));
return this.deck.get(i);
}
public Optional<PegasusGame.PowerHistoryEntity.Builder> getByEntityId(Integer i) { return this.deck.stream().filter(c -> c.getEntity() == i).findFirst(); }
public Integer getSize() {
return this.deck.values().size();
return this.deck.size();
}
public void addCard(PegasusGame.PowerHistoryEntity.Builder b) {
this.deck.put(b.getName(), b);
this.deck.add(b);
}
public void updateCard(PegasusGame.PowerHistoryEntity.Builder b) {
deck.put(b.getName(), b);
public void updateCard(PegasusGame.PowerHistoryEntity.Builder b, Integer i) {
deck.set(i, b);
}
public List<PegasusGame.PowerHistoryEntity.Builder> getHandCards() {
@ -42,7 +42,6 @@ public class GameDeck {
public List<PegasusGame.PowerHistoryEntity.Builder> getCardsByTag(GameTag tag, Integer val) {
return deck
.values()
.stream()
.filter(c -> c.getTagsList()
.stream()
@ -51,10 +50,7 @@ public class GameDeck {
.collect(Collectors.toList());
}
private List<String> getKeys() {
return this.deck.keySet()
.stream()
.sorted()
.collect(Collectors.toList());
public void shuffleDeck() {
Collections.shuffle(deck);
}
}