Refactoring game process
This commit is contained in:
parent
cc1b189ab0
commit
073994fadf
@ -2,12 +2,11 @@ package com.alterdekim.hearthhack.component;
|
|||||||
|
|
||||||
import com.alterdekim.PegasusGame;
|
import com.alterdekim.PegasusGame;
|
||||||
import com.alterdekim.PegasusShared;
|
import com.alterdekim.PegasusShared;
|
||||||
|
import com.alterdekim.hearthhack.component.interfaces.GamePacketCallback;
|
||||||
import com.alterdekim.hearthhack.game.*;
|
import com.alterdekim.hearthhack.game.*;
|
||||||
import com.alterdekim.hearthhack.util.PegasusPacket;
|
import com.alterdekim.hearthhack.util.PegasusPacket;
|
||||||
import com.alterdekim.hearthhack.util.Util;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.security.core.parameters.P;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -22,38 +21,29 @@ import static com.alterdekim.PegasusGame.Option.Type.END_TURN;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class GameConnection extends Thread {
|
public class GameConnection extends Thread {
|
||||||
private final Socket client;
|
|
||||||
private final GameServer parent;
|
private final GameServer parent;
|
||||||
|
|
||||||
|
private final Socket client;
|
||||||
private OutputStream outToClient;
|
private OutputStream outToClient;
|
||||||
|
private long gameId = 0L;
|
||||||
private Long id;
|
private long playerId = 0L;
|
||||||
|
|
||||||
private boolean isLoggedIn = false;
|
private boolean isLoggedIn = false;
|
||||||
|
|
||||||
public void stopListeningAndDisconnect() {
|
|
||||||
try {
|
|
||||||
this.client.close();
|
|
||||||
this.interrupt();
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processPacket( PegasusPacket packet ) throws Exception {
|
private void processPacket( PegasusPacket packet ) throws Exception {
|
||||||
log.info("PegasusPacket: type={}, context={}, size={}", packet.getType(), packet.getContext(), packet.getSize());
|
log.info("PegasusPacket: type={}, context={}, size={}", packet.getType(), packet.getContext(), packet.getSize());
|
||||||
if( !isLoggedIn && packet.getType() != 168 ) stopListeningAndDisconnect();
|
if( !isLoggedIn && packet.getType() != 168 ) stopListeningAndDisconnect();
|
||||||
switch (packet.getType()) {
|
if( packet.getType() == 168 ) {
|
||||||
case 168:
|
|
||||||
PegasusGame.Handshake handshake = PegasusGame.Handshake.parseFrom((byte[]) packet.getBody());
|
PegasusGame.Handshake handshake = PegasusGame.Handshake.parseFrom((byte[]) packet.getBody());
|
||||||
log.info("Handshake: {}", handshake);
|
log.info("Handshake: {}", handshake);
|
||||||
// game_handle: gameId
|
// game_handle: gameId
|
||||||
// client_handle: userId
|
// client_handle: userId
|
||||||
// password: roomPassword
|
// password: roomPassword
|
||||||
GameRoom room = parent.getGamePool().getGameRoomById((long) handshake.getGameHandle());
|
Optional<GameRoom> room = parent.getGamePool().getGameRoomById((long) handshake.getGameHandle());
|
||||||
log.info("Handshake check: {}", room);
|
log.info("Handshake check: {}", room);
|
||||||
if( room == null ||
|
if( room.isEmpty() ||
|
||||||
!room.getPassword().equals(handshake.getPassword()) ||
|
!room.get().getPassword().equals(handshake.getPassword()) ||
|
||||||
!room.getPlayers().stream().anyMatch(p -> p.getUserId().longValue() == handshake.getClientHandle()) ) {
|
!room.get().getPlayers().stream().anyMatch(p -> p.getUserId().longValue() == handshake.getClientHandle()) ) {
|
||||||
log.error("Handshake failed!");
|
log.error("Handshake failed!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -69,8 +59,31 @@ public class GameConnection extends Thread {
|
|||||||
PegasusPacket result = new PegasusPacket(16, 0, setup);
|
PegasusPacket result = new PegasusPacket(16, 0, setup);
|
||||||
this.send(result);
|
this.send(result);
|
||||||
this.isLoggedIn = true;
|
this.isLoggedIn = true;
|
||||||
break;
|
this.gameId = (long) handshake.getGameHandle();
|
||||||
case 1:
|
this.playerId = (long) handshake.getClientHandle();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( packet.getType() == 115 ) {
|
||||||
|
pong();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// pass to GameRoom
|
||||||
|
Optional<GameRoom> room = this.parent.getGamePool().getGameRoomById(gameId);
|
||||||
|
room.ifPresent(gameRoom -> {
|
||||||
|
gameRoom.updateCallback(this.playerId, packet1 -> {
|
||||||
|
try {
|
||||||
|
send(packet1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
gameRoom.getIncomeQueue().add(new IncomeGamePacket(this.playerId, packet));
|
||||||
|
});
|
||||||
|
//sendThings();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: abolish that thing
|
||||||
|
private void sendThings() throws Exception {
|
||||||
// GetGameState
|
// GetGameState
|
||||||
PegasusGame.PowerHistory powerHistory = PegasusGame.PowerHistory.newBuilder()
|
PegasusGame.PowerHistory powerHistory = PegasusGame.PowerHistory.newBuilder()
|
||||||
.addList(PegasusGame.PowerHistoryData.newBuilder()
|
.addList(PegasusGame.PowerHistoryData.newBuilder()
|
||||||
@ -1691,8 +1704,8 @@ public class GameConnection extends Thread {
|
|||||||
log.info("Packet: {}", powerHistory);
|
log.info("Packet: {}", powerHistory);
|
||||||
this.send(new PegasusPacket(19, 0, powerHistory.toByteArray()));
|
this.send(new PegasusPacket(19, 0, powerHistory.toByteArray()));
|
||||||
|
|
||||||
PegasusGame.GetGameState state = PegasusGame.GetGameState.parseFrom((byte[]) packet.getBody());
|
/* PegasusGame.GetGameState state = PegasusGame.GetGameState.parseFrom((byte[]) packet.getBody());
|
||||||
log.info("GetGameState: {}", state);
|
log.info("GetGameState: {}", state);*/
|
||||||
|
|
||||||
powerHistory = PegasusGame.PowerHistory.newBuilder()
|
powerHistory = PegasusGame.PowerHistory.newBuilder()
|
||||||
.addList(PegasusGame.PowerHistoryData.newBuilder()
|
.addList(PegasusGame.PowerHistoryData.newBuilder()
|
||||||
@ -2412,6 +2425,12 @@ public class GameConnection extends Thread {
|
|||||||
|
|
||||||
this.send(new PegasusPacket(19, 0, powerHistory));
|
this.send(new PegasusPacket(19, 0, powerHistory));
|
||||||
|
|
||||||
|
///////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////
|
||||||
|
|
||||||
|
|
||||||
PegasusGame.AllOptions allOptions = PegasusGame.AllOptions.newBuilder()
|
PegasusGame.AllOptions allOptions = PegasusGame.AllOptions.newBuilder()
|
||||||
.setId(1)
|
.setId(1)
|
||||||
@ -2640,29 +2659,12 @@ public class GameConnection extends Thread {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
this.send(new PegasusPacket( 14, 0, allOptions.toByteArray()));
|
this.send(new PegasusPacket( 14, 0, allOptions.toByteArray()));
|
||||||
break;
|
|
||||||
case 115:
|
|
||||||
pong();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pong() throws Exception {
|
private void pong() throws Exception {
|
||||||
this.send(new PegasusPacket(116, 0, PegasusGame.Pong.newBuilder().build()));
|
this.send(new PegasusPacket(116, 0, PegasusGame.Pong.newBuilder().build()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void send(PegasusPacket pp) throws Exception {
|
|
||||||
this.outToClient.write(pp.Encode());
|
|
||||||
this.outToClient.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendRaw(byte[] data) throws Exception {
|
|
||||||
this.outToClient.write(data);
|
|
||||||
this.outToClient.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@ -2680,7 +2682,7 @@ public class GameConnection extends Thread {
|
|||||||
int offset = 0;
|
int offset = 0;
|
||||||
while( offset < r.length ) {
|
while( offset < r.length ) {
|
||||||
offset += pp.Decode(r, offset, r.length);
|
offset += pp.Decode(r, offset, r.length);
|
||||||
processPacket(pp);
|
this.processPacket(pp);
|
||||||
}
|
}
|
||||||
baos.reset();
|
baos.reset();
|
||||||
}
|
}
|
||||||
@ -2694,4 +2696,18 @@ public class GameConnection extends Thread {
|
|||||||
log.error(e.getMessage());
|
log.error(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void stopListeningAndDisconnect() {
|
||||||
|
try {
|
||||||
|
this.client.close();
|
||||||
|
this.interrupt();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(PegasusPacket pp) throws Exception {
|
||||||
|
this.outToClient.write(pp.Encode());
|
||||||
|
this.outToClient.flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ public class GamePool {
|
|||||||
roomService.clear();
|
roomService.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameRoom getGameRoomById(Long id) {
|
public Optional<GameRoom> getGameRoomById(Long id) {
|
||||||
return games.get(id);
|
return Optional.ofNullable(games.get(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,129 @@
|
|||||||
package com.alterdekim.hearthhack.component;
|
package com.alterdekim.hearthhack.component;
|
||||||
|
|
||||||
|
import com.alterdekim.hearthhack.component.interfaces.GamePacketCallback;
|
||||||
|
import com.alterdekim.hearthhack.component.interfaces.IGameRoom;
|
||||||
import com.alterdekim.hearthhack.dto.RoomPlayerDTO;
|
import com.alterdekim.hearthhack.dto.RoomPlayerDTO;
|
||||||
|
import com.alterdekim.hearthhack.game.GameState;
|
||||||
|
import com.alterdekim.hearthhack.game.IncomeGamePacket;
|
||||||
|
import com.alterdekim.hearthhack.game.OutcomeGamePacket;
|
||||||
import com.alterdekim.hearthhack.service.UserService;
|
import com.alterdekim.hearthhack.service.UserService;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.ToString;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ToString
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class GameRoom {
|
public class GameRoom extends Thread implements IGameRoom {
|
||||||
@Getter
|
@Getter
|
||||||
private final List<RoomPlayerDTO> players;
|
private final List<RoomPlayerDTO> players;
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<Long, GamePacketCallback> callbacks;
|
||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final String password;
|
private final String password;
|
||||||
|
|
||||||
|
private GameState globalState;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private ConcurrentLinkedQueue<IncomeGamePacket> incomeQueue;
|
||||||
|
private ConcurrentLinkedQueue<OutcomeGamePacket> outcomeQueue;
|
||||||
|
|
||||||
public GameRoom(List<RoomPlayerDTO> players, UserService userService, String password) {
|
public GameRoom(List<RoomPlayerDTO> players, UserService userService, String password) {
|
||||||
this.players = players;
|
this.players = players;
|
||||||
this.userService = userService;
|
this.userService = userService;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
log.info("New GameRoom!");
|
this.incomeQueue = new ConcurrentLinkedQueue<>();
|
||||||
|
this.outcomeQueue = new ConcurrentLinkedQueue<>();
|
||||||
|
this.callbacks = new ConcurrentHashMap<>();
|
||||||
|
this.globalState = GameState.CreateGame;
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
this.outcomeQueue.poll();*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processIncomePacket(IncomeGamePacket packet) {
|
||||||
|
if( packet.getPacket().getType() != 1) return;
|
||||||
|
List<OutcomeGamePacket> l = this.outcomeQueue.stream()
|
||||||
|
.filter(p -> p.getPlayerId().longValue() == packet.getPlayerId().longValue())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
GamePacketCallback callback = this.callbacks.get(packet.getPlayerId());
|
||||||
|
if (callback == null) return;
|
||||||
|
l.forEach(p -> callback.onMessage(p.getPacket()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateGameState() {
|
||||||
|
// giant switch
|
||||||
|
switch (this.globalState) {
|
||||||
|
case CreateGame -> createGameEntity();
|
||||||
|
case CreatePlayers -> createPlayerEntity();
|
||||||
|
case CreateDecks -> createDeckEntities();
|
||||||
|
case CreateHeroes -> createPlayerHeroEntity();
|
||||||
|
case CreateHeroPowers -> createPlayerHeroPowerEntity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createPlayerEntity() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createDeckEntities() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createCardEntity() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createPlayerHeroEntity() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createPlayerHeroPowerEntity() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<RoomPlayerDTO> findPlayerById(Long id) {
|
||||||
|
return players.stream().filter(p -> p.getUserId().longValue() == id.longValue()).findFirst();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ public class GameServer {
|
|||||||
while(true) {
|
while(true) {
|
||||||
Socket client = this.serverSocket.accept();
|
Socket client = this.serverSocket.accept();
|
||||||
log.info("New WOW Connection Established From {}", client.getInetAddress().toString());
|
log.info("New WOW Connection Established From {}", client.getInetAddress().toString());
|
||||||
GameConnection c = new GameConnection(client, this);
|
GameConnection c = new GameConnection(this, client);
|
||||||
this.connections.add(c);
|
this.connections.add(c);
|
||||||
c.start();
|
c.start();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.alterdekim.hearthhack.component.interfaces;
|
||||||
|
|
||||||
|
import com.alterdekim.hearthhack.util.PegasusPacket;
|
||||||
|
|
||||||
|
public interface GamePacketCallback {
|
||||||
|
void onMessage(PegasusPacket packet);
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.alterdekim.hearthhack.component.interfaces;
|
||||||
|
|
||||||
|
public interface IGameRoom {
|
||||||
|
void createGameEntity();
|
||||||
|
void createPlayerEntity();
|
||||||
|
void createDeckEntities();
|
||||||
|
void createCardEntity();
|
||||||
|
void createPlayerHeroEntity();
|
||||||
|
void createPlayerHeroPowerEntity();
|
||||||
|
}
|
16
src/main/java/com/alterdekim/hearthhack/game/GameState.java
Normal file
16
src/main/java/com/alterdekim/hearthhack/game/GameState.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package com.alterdekim.hearthhack.game;
|
||||||
|
|
||||||
|
public enum GameState {
|
||||||
|
CreateGame,
|
||||||
|
CreatePlayers,
|
||||||
|
CreateDecks,
|
||||||
|
CreateHeroes,
|
||||||
|
CreateHeroPowers,
|
||||||
|
Running;
|
||||||
|
|
||||||
|
public GameState next() {
|
||||||
|
GameState[] states = GameState.values();
|
||||||
|
int i = this.ordinal()+1 >= states.length ? 0 : this.ordinal()+1;
|
||||||
|
return states[i];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.alterdekim.hearthhack.game;
|
||||||
|
|
||||||
|
import com.alterdekim.hearthhack.util.PegasusPacket;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class IncomeGamePacket {
|
||||||
|
private final Long playerId;
|
||||||
|
private final PegasusPacket packet;
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.alterdekim.hearthhack.game;
|
||||||
|
|
||||||
|
import com.alterdekim.hearthhack.util.PegasusPacket;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class OutcomeGamePacket {
|
||||||
|
private final Long playerId;
|
||||||
|
private final PegasusPacket packet;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user