summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/main/java/kz/ilotterytea/frogartha/entities/PlayerEntity.java5
-rw-r--r--core/src/main/java/kz/ilotterytea/frogartha/screens/GameScreen.java26
-rw-r--r--core/src/main/java/kz/ilotterytea/frogartha/screens/MenuScreen.java2
-rw-r--r--core/src/main/java/kz/ilotterytea/frogartha/sessions/IdentityClient.java11
-rw-r--r--core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionClient.java35
-rw-r--r--core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionHandlers.java103
-rw-r--r--server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java32
-rw-r--r--server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java10
-rw-r--r--server/src/main/java/kz/ilotterytea/frogartha/server/Room.java58
-rw-r--r--server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java75
-rw-r--r--shared/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java4
-rw-r--r--shared/src/main/java/kz/ilotterytea/frogartha/domain/RoomTopic.java5
-rw-r--r--shared/src/main/java/kz/ilotterytea/frogartha/domain/actions/JoinRoomAction.java32
-rw-r--r--shared/src/main/java/kz/ilotterytea/frogartha/domain/actions/LeaveRoomAction.java20
-rw-r--r--shared/src/main/java/kz/ilotterytea/frogartha/domain/events/IdentifiedEvent.java25
-rw-r--r--shared/src/main/java/kz/ilotterytea/frogartha/domain/events/PlayerJoinedRoomEvent.java35
-rw-r--r--shared/src/main/java/kz/ilotterytea/frogartha/domain/events/PlayerLeftRoomEvent.java25
-rw-r--r--shared/src/main/java/kz/ilotterytea/frogartha/domain/events/SenderJoinedRoomEvent.java51
-rw-r--r--shared/src/main/java/kz/ilotterytea/frogartha/domain/events/SenderLeftRoomEvent.java25
-rw-r--r--shared/src/main/java/kz/ilotterytea/frogartha/domain/server/Acknowledge.java42
-rw-r--r--shared/src/main/java/kz/ilotterytea/frogartha/exceptions/PlayerKickException.java8
-rw-r--r--shared/src/main/java/kz/ilotterytea/frogartha/utils/SerializerUtils.java16
22 files changed, 573 insertions, 72 deletions
diff --git a/core/src/main/java/kz/ilotterytea/frogartha/entities/PlayerEntity.java b/core/src/main/java/kz/ilotterytea/frogartha/entities/PlayerEntity.java
index 8cc70bc..8264c8f 100644
--- a/core/src/main/java/kz/ilotterytea/frogartha/entities/PlayerEntity.java
+++ b/core/src/main/java/kz/ilotterytea/frogartha/entities/PlayerEntity.java
@@ -1,10 +1,9 @@
package kz.ilotterytea.frogartha.entities;
-import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector3;
import kz.ilotterytea.frogartha.FrogarthaConstants;
+import kz.ilotterytea.frogartha.FrogarthaGame;
public class PlayerEntity extends RenderableEntity {
protected Vector3 startPosition, endPosition;
@@ -13,7 +12,7 @@ public class PlayerEntity extends RenderableEntity {
protected boolean isJumping;
public PlayerEntity() {
- super(new Texture(Gdx.files.internal("sprites/player/player.png")));
+ super(FrogarthaGame.getInstance().getAssetManager().get("sprites/player/player.png"));
this.endPosition = Vector3.Zero;
this.startPosition = Vector3.Zero;
}
diff --git a/core/src/main/java/kz/ilotterytea/frogartha/screens/GameScreen.java b/core/src/main/java/kz/ilotterytea/frogartha/screens/GameScreen.java
index 3da9d55..421a458 100644
--- a/core/src/main/java/kz/ilotterytea/frogartha/screens/GameScreen.java
+++ b/core/src/main/java/kz/ilotterytea/frogartha/screens/GameScreen.java
@@ -11,7 +11,9 @@ import com.badlogic.gdx.graphics.g3d.decals.CameraGroupStrategy;
import com.badlogic.gdx.graphics.g3d.decals.DecalBatch;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.math.Vector3;
+import kz.ilotterytea.frogartha.FrogarthaGame;
import kz.ilotterytea.frogartha.entities.LocalPlayerEntity;
+import kz.ilotterytea.frogartha.entities.PlayerEntity;
import net.mgsx.gltf.scene3d.attributes.PBRCubemapAttribute;
import net.mgsx.gltf.scene3d.attributes.PBRTextureAttribute;
import net.mgsx.gltf.scene3d.lights.DirectionalShadowLight;
@@ -21,19 +23,34 @@ import net.mgsx.gltf.scene3d.scene.SceneManager;
import net.mgsx.gltf.scene3d.scene.SceneSkybox;
import net.mgsx.gltf.scene3d.utils.IBLBuilder;
+import java.util.HashMap;
+import java.util.Map;
+
public class GameScreen implements Screen {
+ private FrogarthaGame game;
+
private PerspectiveCamera camera;
private SceneManager sceneManager;
private DecalBatch decalBatch;
private LocalPlayerEntity playerEntity;
+ private HashMap<Integer, PlayerEntity> playerEntityMap;
+
@Override
public void show() {
+ game = FrogarthaGame.getInstance();
+
create3D();
playerEntity = new LocalPlayerEntity(camera);
playerEntity.setPosition(0f, 1f, 0f);
+
+ playerEntityMap = new HashMap<>();
+
+ for (Integer id : game.getSessionClient().getPlayerDataMap().keySet()) {
+ playerEntityMap.put(id, new PlayerEntity());
+ }
}
@Override
@@ -45,6 +62,11 @@ public class GameScreen implements Screen {
playerEntity.update(delta);
playerEntity.render(decalBatch);
+ for (Map.Entry<Integer, PlayerEntity> player : playerEntityMap.entrySet()) {
+ player.getValue().update(delta);
+ player.getValue().render(decalBatch);
+ }
+
decalBatch.flush();
}
@@ -130,4 +152,8 @@ public class GameScreen implements Screen {
public LocalPlayerEntity getPlayerEntity() {
return playerEntity;
}
+
+ public HashMap<Integer, PlayerEntity> getPlayerEntityMap() {
+ return playerEntityMap;
+ }
}
diff --git a/core/src/main/java/kz/ilotterytea/frogartha/screens/MenuScreen.java b/core/src/main/java/kz/ilotterytea/frogartha/screens/MenuScreen.java
index 761835e..9f716f6 100644
--- a/core/src/main/java/kz/ilotterytea/frogartha/screens/MenuScreen.java
+++ b/core/src/main/java/kz/ilotterytea/frogartha/screens/MenuScreen.java
@@ -37,7 +37,7 @@ public class MenuScreen implements Screen {
stage.act(delta);
stage.draw();
- if (game.getIdentityClient().isAuthorized()) {
+ if (game.getIdentityClient().isInRoom()) {
game.setScreen(new GameScreen());
}
}
diff --git a/core/src/main/java/kz/ilotterytea/frogartha/sessions/IdentityClient.java b/core/src/main/java/kz/ilotterytea/frogartha/sessions/IdentityClient.java
index 1e09e8e..64e7270 100644
--- a/core/src/main/java/kz/ilotterytea/frogartha/sessions/IdentityClient.java
+++ b/core/src/main/java/kz/ilotterytea/frogartha/sessions/IdentityClient.java
@@ -8,7 +8,7 @@ public class IdentityClient {
private final FrogarthaGame game;
private String username;
- private boolean isProcessing, isAuthorized;
+ private boolean isProcessing, isAuthorized, inRoom;
public IdentityClient() {
this.log = new Logger(IdentityClient.class);
@@ -18,6 +18,7 @@ public class IdentityClient {
this.isProcessing = false;
this.isAuthorized = false;
+ this.inRoom = false;
}
@@ -38,6 +39,14 @@ public class IdentityClient {
isAuthorized = authorized;
}
+ public boolean isInRoom() {
+ return inRoom;
+ }
+
+ public void setInRoom(boolean inRoom) {
+ this.inRoom = inRoom;
+ }
+
public boolean isProcessing() {
return isProcessing;
}
diff --git a/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionClient.java b/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionClient.java
index 738ee3a..e8b32e3 100644
--- a/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionClient.java
+++ b/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionClient.java
@@ -8,18 +8,22 @@ import com.github.czyzby.websocket.serialization.impl.ManualSerializer;
import kz.ilotterytea.frogartha.FrogarthaConstants;
import kz.ilotterytea.frogartha.FrogarthaGame;
import kz.ilotterytea.frogartha.domain.Identity;
-import kz.ilotterytea.frogartha.domain.events.ChangedDirectionEvent;
-import kz.ilotterytea.frogartha.domain.events.PlayerJumpEvent;
-import kz.ilotterytea.frogartha.domain.server.Acknowledge;
+import kz.ilotterytea.frogartha.domain.PlayerData;
+import kz.ilotterytea.frogartha.domain.events.*;
import kz.ilotterytea.frogartha.exceptions.PlayerKickException;
import kz.ilotterytea.frogartha.utils.Logger;
import kz.ilotterytea.frogartha.utils.SerializerUtils;
+import java.util.HashMap;
+
public class SessionClient implements WebSocketListener {
private final Logger log;
private final FrogarthaGame game;
private final WebSocket connection;
private final ManualSerializer serializer;
+ private final HashMap<Integer, PlayerData> playerDataMap;
+
+ private int connectionId;
public SessionClient() {
this.connection = WebSockets.newSocket(FrogarthaConstants.URLS.SESSION_WSS);
@@ -31,6 +35,7 @@ public class SessionClient implements WebSocketListener {
this.log = new Logger(SessionClient.class);
this.game = FrogarthaGame.getInstance();
+ this.playerDataMap = new HashMap<>();
}
@Override
@@ -61,12 +66,20 @@ public class SessionClient implements WebSocketListener {
throw new RuntimeException("Deserialized packet is null");
}
- if (obj instanceof Acknowledge) {
- SessionHandlers.handleAcknowledge((Acknowledge) obj);
+ if (obj instanceof IdentifiedEvent) {
+ SessionHandlers.handleIdentifiedEvent((IdentifiedEvent) obj);
} else if (obj instanceof PlayerJumpEvent) {
SessionHandlers.handlePlayerJumpEvent((PlayerJumpEvent) obj);
} else if (obj instanceof ChangedDirectionEvent) {
SessionHandlers.handleChangedDirectionEvent((ChangedDirectionEvent) obj);
+ } else if (obj instanceof SenderJoinedRoomEvent) {
+ SessionHandlers.handleSenderJoinedRoomEvent((SenderJoinedRoomEvent) obj);
+ } else if (obj instanceof SenderLeftRoomEvent) {
+ SessionHandlers.handleSenderLeftRoomEvent((SenderLeftRoomEvent) obj);
+ } else if (obj instanceof PlayerJoinedRoomEvent) {
+ SessionHandlers.handlePlayerJoinedRoomEvent((PlayerJoinedRoomEvent) obj);
+ } else if (obj instanceof PlayerLeftRoomEvent) {
+ SessionHandlers.handlePlayerLeftRoomEvent((PlayerLeftRoomEvent) obj);
} else if (obj instanceof PlayerKickException) {
throw (PlayerKickException) obj;
}
@@ -103,4 +116,16 @@ public class SessionClient implements WebSocketListener {
public void updateIdentity() {
send(new Identity(game.getIdentityClient().getUsername()));
}
+
+ public int getConnectionId() {
+ return connectionId;
+ }
+
+ public void setConnectionId(int connectionId) {
+ this.connectionId = connectionId;
+ }
+
+ public HashMap<Integer, PlayerData> getPlayerDataMap() {
+ return playerDataMap;
+ }
}
diff --git a/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionHandlers.java b/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionHandlers.java
index 2fc50b8..c7abe3e 100644
--- a/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionHandlers.java
+++ b/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionHandlers.java
@@ -2,24 +2,29 @@ package kz.ilotterytea.frogartha.sessions;
import com.badlogic.gdx.math.Vector3;
import kz.ilotterytea.frogartha.FrogarthaGame;
-import kz.ilotterytea.frogartha.domain.events.ChangedDirectionEvent;
-import kz.ilotterytea.frogartha.domain.events.PlayerJumpEvent;
-import kz.ilotterytea.frogartha.domain.server.Acknowledge;
+import kz.ilotterytea.frogartha.domain.PlayerData;
+import kz.ilotterytea.frogartha.domain.RoomTopic;
+import kz.ilotterytea.frogartha.domain.actions.JoinRoomAction;
+import kz.ilotterytea.frogartha.domain.events.*;
import kz.ilotterytea.frogartha.entities.PlayerEntity;
import kz.ilotterytea.frogartha.screens.GameScreen;
+import kz.ilotterytea.frogartha.screens.MenuScreen;
import kz.ilotterytea.frogartha.utils.Logger;
+import java.util.HashMap;
+import java.util.Map;
+
public class SessionHandlers {
private static final Logger log = new Logger(SessionHandlers.class);
private static final FrogarthaGame game = FrogarthaGame.getInstance();
private static final SessionClient client = game.getSessionClient();
- public static void handleAcknowledge(Acknowledge acknowledge) {
- log.log("The server was acknowledged: {}", acknowledge);
+ public static void handleIdentifiedEvent(IdentifiedEvent event) {
+ log.log("The server identified me!");
- if (acknowledge.getCode() == Acknowledge.AcknowledgeCode.IDENTIFIED) {
- game.getIdentityClient().setAuthorized(true);
- }
+ client.setConnectionId(event.getPlayerId());
+ game.getIdentityClient().setAuthorized(true);
+ client.send(new JoinRoomAction(RoomTopic.POND));
}
public static void handlePlayerJumpEvent(PlayerJumpEvent event) {
@@ -29,7 +34,22 @@ public class SessionHandlers {
}
GameScreen screen = (GameScreen) game.getScreen();
- PlayerEntity entity = screen.getPlayerEntity();
+ PlayerEntity entity = null;
+
+ if (event.getPlayerId() == client.getConnectionId()) {
+ entity = screen.getPlayerEntity();
+ } else {
+ for (Map.Entry<Integer, PlayerEntity> entityEntry : screen.getPlayerEntityMap().entrySet()) {
+ if (entityEntry.getKey() != event.getPlayerId()) continue;
+ entity = entityEntry.getValue();
+ break;
+ }
+ }
+
+ if (entity == null) {
+ log.log("No player ID {}", event.getPlayerId());
+ return;
+ }
entity.setJumpStrength(event.getJumpStrength());
entity.setStartPosition(event.getStartPosition());
@@ -44,10 +64,73 @@ public class SessionHandlers {
}
GameScreen screen = (GameScreen) game.getScreen();
- PlayerEntity entity = screen.getPlayerEntity();
+ PlayerEntity entity = null;
+
+ if (event.getPlayerId() == client.getConnectionId()) {
+ entity = screen.getPlayerEntity();
+ } else {
+ for (Map.Entry<Integer, PlayerEntity> entityEntry : screen.getPlayerEntityMap().entrySet()) {
+ if (entityEntry.getKey() != event.getPlayerId()) continue;
+ entity = entityEntry.getValue();
+ break;
+ }
+ }
+
+ if (entity == null) {
+ log.log("No player ID {}", event.getPlayerId());
+ return;
+ }
Vector3 direction = event.getDirection();
entity.setDirection(direction.x, entity.getPosition().y, direction.z);
}
+
+ public static void handleSenderJoinedRoomEvent(SenderJoinedRoomEvent event) {
+ if (game.getScreen().getClass().equals(GameScreen.class)) {
+ log.log("The screen is already GameScreen, but the session received SenderJoinedRoomEvent");
+ return;
+ }
+
+ HashMap<Integer, PlayerData> map = new HashMap<>();
+
+ for (int i = 0; i < event.getPlayers().size(); i++) {
+ Integer id = event.getIds().get(i);
+ PlayerData data = event.getPlayers().get(i);
+ map.put(id, data);
+ }
+
+ client.getPlayerDataMap().putAll(map);
+ game.getIdentityClient().setInRoom(true);
+ }
+
+ public static void handleSenderLeftRoomEvent(SenderLeftRoomEvent event) {
+ if (!game.getScreen().getClass().equals(GameScreen.class)) {
+ log.log("The screen is not GameScreen, but the session received SenderLeftRoomEvent");
+ return;
+ }
+
+ client.getPlayerDataMap().clear();
+ game.setScreen(new MenuScreen());
+ }
+
+ public static void handlePlayerJoinedRoomEvent(PlayerJoinedRoomEvent event) {
+ if (!game.getScreen().getClass().equals(GameScreen.class)) {
+ log.log("The screen is not GameScreen, but the session received PlayerJoinedRoomEvent");
+ return;
+ }
+
+ GameScreen screen = (GameScreen) game.getScreen();
+ screen.getPlayerEntityMap().put(event.getPlayerId(), new PlayerEntity());
+ }
+
+ public static void handlePlayerLeftRoomEvent(PlayerLeftRoomEvent event) {
+ if (!game.getScreen().getClass().equals(GameScreen.class)) {
+ log.log("The screen is not GameScreen, but the session received PlayerLeftRoomEvent");
+ return;
+ }
+
+ GameScreen screen = (GameScreen) game.getScreen();
+ screen.getPlayerEntityMap().remove(event.getPlayerId());
+ }
}
diff --git a/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java b/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java
index 24a607d..dca0afd 100644
--- a/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java
+++ b/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java
@@ -3,6 +3,8 @@ package kz.ilotterytea.frogartha.server;
import com.github.czyzby.websocket.serialization.impl.ManualSerializer;
import kz.ilotterytea.frogartha.domain.Identity;
import kz.ilotterytea.frogartha.domain.actions.ChangedDirectionAction;
+import kz.ilotterytea.frogartha.domain.actions.JoinRoomAction;
+import kz.ilotterytea.frogartha.domain.actions.LeaveRoomAction;
import kz.ilotterytea.frogartha.domain.actions.PlayerJumpAction;
import kz.ilotterytea.frogartha.exceptions.PlayerKickException;
import kz.ilotterytea.frogartha.utils.Logger;
@@ -21,14 +23,18 @@ public class FrogarthaServer extends WebSocketServer {
private static FrogarthaServer instance;
private final Logger log;
+
private final ArrayList<PlayerConnection> players;
+ private final ArrayList<Room> rooms;
private final ManualSerializer serializer;
private FrogarthaServer() {
super(new InetSocketAddress(20015));
this.log = new Logger(FrogarthaServer.class);
+
this.players = new ArrayList<>();
+ this.rooms = new ArrayList<>();
this.serializer = new ManualSerializer();
SerializerUtils.registerTypes(serializer);
@@ -46,6 +52,7 @@ public class FrogarthaServer extends WebSocketServer {
Optional<PlayerConnection> player = this.players.stream().filter((x) -> x.getConnection().equals(webSocket)).findFirst();
if (player.isPresent()) {
+ kickPlayerFromRoom(player.get());
log.log("{} has left! Reason: {} {}", player.get(), i, s);
this.players.remove(player.get());
} else {
@@ -55,7 +62,12 @@ public class FrogarthaServer extends WebSocketServer {
@Override
public void onMessage(WebSocket webSocket, String s) {
- this.players.removeIf((x) -> x.getConnection().equals(webSocket));
+ Optional<PlayerConnection> optionalPlayerConnection = this.players.stream()
+ .filter((x) -> x.getConnection().equals(webSocket))
+ .findFirst();
+
+ optionalPlayerConnection.ifPresent((x) -> kickConnection(x, PlayerKickException.internalServerError()));
+
webSocket.send("Invalid input.");
webSocket.close(CloseFrame.UNEXPECTED_CONDITION);
}
@@ -84,6 +96,10 @@ public class FrogarthaServer extends WebSocketServer {
ServerHandlers.handlePlayerJumpAction(player, (PlayerJumpAction) obj);
} else if (obj instanceof ChangedDirectionAction) {
ServerHandlers.handleChangedDirectionAction(player, (ChangedDirectionAction) obj);
+ } else if (obj instanceof JoinRoomAction) {
+ ServerHandlers.handleJoinRoomAction(player, (JoinRoomAction) obj);
+ } else if (obj instanceof LeaveRoomAction) {
+ ServerHandlers.handleLeaveRoomAction(player, (LeaveRoomAction) obj);
} else {
throw PlayerKickException.internalServerError();
}
@@ -108,12 +124,22 @@ public class FrogarthaServer extends WebSocketServer {
}
public void kickConnection(PlayerConnection player, PlayerKickException exception) {
+ kickPlayerFromRoom(player);
player.send(exception);
player.getConnection().close();
players.remove(player);
log.log("Kicked out {}! Reason: {}", player, exception.getMessage());
}
+ public void kickPlayerFromRoom(PlayerConnection player) {
+ if (player.getRoom() == null) return;
+ Room room = player.getRoom();
+ room.removePlayer(player);
+ if (room.getPlayers().isEmpty()) {
+ this.rooms.remove(room);
+ }
+ }
+
public static FrogarthaServer getInstance() {
if (instance == null) instance = new FrogarthaServer();
return instance;
@@ -123,6 +149,10 @@ public class FrogarthaServer extends WebSocketServer {
return players;
}
+ public ArrayList<Room> getRooms() {
+ return rooms;
+ }
+
public ManualSerializer getSerializer() {
return serializer;
}
diff --git a/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java b/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java
index f30dcfe..56dd695 100644
--- a/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java
+++ b/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java
@@ -10,6 +10,7 @@ public class PlayerConnection extends PlayerData {
private final int id;
private final WebSocket connection;
+ private Room room;
private final Timestamp connectedTimestamp;
@@ -18,6 +19,7 @@ public class PlayerConnection extends PlayerData {
this.id = TOTAL_CONNECTION_IDS;
TOTAL_CONNECTION_IDS++;
+ this.room = null;
this.connectedTimestamp = new Timestamp(System.currentTimeMillis());
}
@@ -38,6 +40,14 @@ public class PlayerConnection extends PlayerData {
return connection;
}
+ public Room getRoom() {
+ return room;
+ }
+
+ public void setRoom(Room room) {
+ this.room = room;
+ }
+
public Timestamp getConnectedTimestamp() {
return connectedTimestamp;
}
diff --git a/server/src/main/java/kz/ilotterytea/frogartha/server/Room.java b/server/src/main/java/kz/ilotterytea/frogartha/server/Room.java
new file mode 100644
index 0000000..01f92d4
--- /dev/null
+++ b/server/src/main/java/kz/ilotterytea/frogartha/server/Room.java
@@ -0,0 +1,58 @@
+package kz.ilotterytea.frogartha.server;
+
+import kz.ilotterytea.frogartha.domain.PlayerData;
+import kz.ilotterytea.frogartha.domain.RoomTopic;
+import kz.ilotterytea.frogartha.domain.events.PlayerJoinedRoomEvent;
+import kz.ilotterytea.frogartha.domain.events.PlayerLeftRoomEvent;
+import kz.ilotterytea.frogartha.domain.events.SenderJoinedRoomEvent;
+import kz.ilotterytea.frogartha.domain.events.SenderLeftRoomEvent;
+
+import java.util.ArrayList;
+import java.util.stream.Collectors;
+
+public class Room {
+ private final RoomTopic topic;
+ private final ArrayList<PlayerConnection> players;
+
+ public Room(RoomTopic topic) {
+ this.topic = topic;
+ this.players = new ArrayList<>();
+ }
+
+ public ArrayList<PlayerConnection> getPlayers() {
+ return players;
+ }
+
+ public void addPlayer(PlayerConnection player) {
+ this.players.forEach((x) -> x.send(new PlayerJoinedRoomEvent(player.getId(), player)));
+ player.send(new SenderJoinedRoomEvent(
+ player.getId(),
+ this.players.stream().map(PlayerConnection::getId).collect(Collectors.toList()),
+ this.players.stream().map((x) -> (PlayerData) x).collect(Collectors.toList())
+ ));
+ player.setRoom(this);
+ this.players.add(player);
+ }
+
+ public void removePlayer(PlayerConnection player) {
+ player.setRoom(null);
+ this.players.remove(player);
+
+ this.players.forEach((x) -> x.send(new PlayerLeftRoomEvent(player.getId())));
+ if (player.getConnection().isOpen()) {
+ player.send(new SenderLeftRoomEvent(player.getId()));
+ }
+ }
+
+ public RoomTopic getTopic() {
+ return topic;
+ }
+
+ @Override
+ public String toString() {
+ return "Room{" +
+ "topic=" + topic +
+ ", playerSize=" + players.size() +
+ '}';
+ }
+}
diff --git a/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java b/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java
index 1cc0e57..c1bdbbe 100644
--- a/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java
+++ b/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java
@@ -5,13 +5,17 @@ import kz.ilotterytea.frogartha.FrogarthaConstants;
import kz.ilotterytea.frogartha.domain.Identity;
import kz.ilotterytea.frogartha.domain.PlayerState;
import kz.ilotterytea.frogartha.domain.actions.ChangedDirectionAction;
+import kz.ilotterytea.frogartha.domain.actions.JoinRoomAction;
+import kz.ilotterytea.frogartha.domain.actions.LeaveRoomAction;
import kz.ilotterytea.frogartha.domain.actions.PlayerJumpAction;
import kz.ilotterytea.frogartha.domain.events.ChangedDirectionEvent;
+import kz.ilotterytea.frogartha.domain.events.IdentifiedEvent;
import kz.ilotterytea.frogartha.domain.events.PlayerJumpEvent;
-import kz.ilotterytea.frogartha.domain.server.Acknowledge;
import kz.ilotterytea.frogartha.exceptions.PlayerKickException;
import kz.ilotterytea.frogartha.utils.Logger;
+import java.util.Optional;
+
public class ServerHandlers {
private static final Logger log = new Logger(ServerHandlers.class);
private static final FrogarthaServer server = FrogarthaServer.getInstance();
@@ -26,11 +30,15 @@ public class ServerHandlers {
}
player.setIdentity(identity);
- player.send(new Acknowledge(Acknowledge.AcknowledgeCode.IDENTIFIED));
+ player.send(new IdentifiedEvent(player.getId()));
log.log("Successfully identified {} for {}", identity, player);
}
public static void handlePlayerJumpAction(PlayerConnection player, PlayerJumpAction action) {
+ if (player.getRoom() == null) {
+ throw PlayerKickException.notInRoom();
+ }
+
PlayerState state = player.getState();
float nowTimestamp = System.currentTimeMillis() / 1000f;
@@ -56,18 +64,75 @@ public class ServerHandlers {
state.setPosition(endPosition.x, endPosition.y, endPosition.z);
- player.send(new PlayerJumpEvent(
+ PlayerJumpEvent event = new PlayerJumpEvent(
player.getId(), startPosition, endPosition, action.getJumpStrength()
- ));
+ );
+ player.send(event);
log.log("{} jumped from {} to {} with strength {}", player, startPosition, endPosition, action.getJumpStrength());
+
+ // broadcasting
+ Room room = player.getRoom();
+ room.getPlayers().forEach((x) -> {
+ if (x.getId() == player.getId()) return;
+ x.send(event);
+ });
}
public static void handleChangedDirectionAction(PlayerConnection player, ChangedDirectionAction action) {
+ if (player.getRoom() == null) {
+ throw PlayerKickException.notInRoom();
+ }
+
PlayerState state = player.getState();
Vector3 direction = action.getDirection();
state.setDirection(direction.x, state.getPosition().y, direction.z);
- player.send(new ChangedDirectionEvent(player.getId(), state.getDirection()));
+ ChangedDirectionEvent event = new ChangedDirectionEvent(player.getId(), state.getDirection());
+ player.send(event);
+
+ // broadcasting
+ Room room = player.getRoom();
+ room.getPlayers().forEach((x) -> {
+ if (x.getId() == player.getId()) return;
+ x.send(event);
+ });
+ }
+
+ public static void handleJoinRoomAction(PlayerConnection player, JoinRoomAction action) {
+ Optional<Room> optionalRoom = server.getRooms().stream()
+ .filter((x) ->
+ x.getPlayers().size() < FrogarthaConstants.Room.MAX_PLAYERS &&
+ x.getTopic().equals(action.getTopic())
+ )
+ .findFirst();
+
+ Room room = optionalRoom.orElse(new Room(action.getTopic()));
+ room.addPlayer(player);
+
+ if (optionalRoom.isEmpty()) {
+ server.getRooms().add(room);
+ }
+
+ log.log("{} joined {}", player, room);
+ }
+
+ public static void handleLeaveRoomAction(PlayerConnection player, LeaveRoomAction action) {
+ Optional<Room> optionalRoom = server.getRooms().stream()
+ .filter((x) -> x.getPlayers().contains(player))
+ .findFirst();
+
+ if (optionalRoom.isEmpty()) {
+ throw PlayerKickException.illegalOperation();
+ }
+
+ Room room = optionalRoom.get();
+ room.removePlayer(player);
+
+ if (room.getPlayers().isEmpty()) {
+ server.getRooms().remove(room);
+ }
+
+ log.log("{} left {}", player, room);
}
}
diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java b/shared/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java
index d5cdb06..84dc6b0 100644
--- a/shared/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java
+++ b/shared/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java
@@ -10,4 +10,8 @@ public class FrogarthaConstants {
public static final float MAX_JUMP_HEIGHT = 2f;
public static final float JUMP_SPEED = 10f;
}
+
+ public static class Room {
+ public static final int MAX_PLAYERS = 30;
+ }
}
diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/RoomTopic.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/RoomTopic.java
new file mode 100644
index 0000000..5b2f47e
--- /dev/null
+++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/RoomTopic.java
@@ -0,0 +1,5 @@
+package kz.ilotterytea.frogartha.domain;
+
+public enum RoomTopic {
+ POND
+}
diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/actions/JoinRoomAction.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/actions/JoinRoomAction.java
new file mode 100644
index 0000000..fa19d27
--- /dev/null
+++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/actions/JoinRoomAction.java
@@ -0,0 +1,32 @@
+package kz.ilotterytea.frogartha.domain.actions;
+
+import com.github.czyzby.websocket.serialization.SerializationException;
+import com.github.czyzby.websocket.serialization.Transferable;
+import com.github.czyzby.websocket.serialization.impl.Deserializer;
+import com.github.czyzby.websocket.serialization.impl.Serializer;
+import kz.ilotterytea.frogartha.domain.RoomTopic;
+
+public class JoinRoomAction implements Transferable<JoinRoomAction> {
+ private RoomTopic topic;
+
+ public JoinRoomAction() {
+ }
+
+ public JoinRoomAction(RoomTopic topic) {
+ this.topic = topic;
+ }
+
+ public RoomTopic getTopic() {
+ return topic;
+ }
+
+ @Override
+ public void serialize(Serializer serializer) throws SerializationException {
+ serializer.serializeInt(topic.ordinal());
+ }
+
+ @Override
+ public JoinRoomAction deserialize(Deserializer deserializer) throws SerializationException {
+ return new JoinRoomAction(RoomTopic.values()[deserializer.deserializeInt()]);
+ }
+}
diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/actions/LeaveRoomAction.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/actions/LeaveRoomAction.java
new file mode 100644
index 0000000..2ae304a
--- /dev/null
+++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/actions/LeaveRoomAction.java
@@ -0,0 +1,20 @@
+package kz.ilotterytea.frogartha.domain.actions;
+
+import com.github.czyzby.websocket.serialization.SerializationException;
+import com.github.czyzby.websocket.serialization.Transferable;
+import com.github.czyzby.websocket.serialization.impl.Deserializer;
+import com.github.czyzby.websocket.serialization.impl.Serializer;
+
+public class LeaveRoomAction implements Transferable<LeaveRoomAction> {
+ public LeaveRoomAction() {
+ }
+
+ @Override
+ public void serialize(Serializer serializer) throws SerializationException {
+ }
+
+ @Override
+ public LeaveRoomAction deserialize(Deserializer deserializer) throws SerializationException {
+ return new LeaveRoomAction();
+ }
+}
diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/IdentifiedEvent.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/IdentifiedEvent.java
new file mode 100644
index 0000000..d2d9e1e
--- /dev/null
+++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/IdentifiedEvent.java
@@ -0,0 +1,25 @@
+package kz.ilotterytea.frogartha.domain.events;
+
+import com.github.czyzby.websocket.serialization.SerializationException;
+import com.github.czyzby.websocket.serialization.Transferable;
+import com.github.czyzby.websocket.serialization.impl.Deserializer;
+import com.github.czyzby.websocket.serialization.impl.Serializer;
+
+public class IdentifiedEvent extends Event implements Transferable<IdentifiedEvent> {
+ public IdentifiedEvent() {
+ }
+
+ public IdentifiedEvent(int playerId) {
+ this.playerId = playerId;
+ }
+
+ @Override
+ public void serialize(Serializer serializer) throws SerializationException {
+ serializer.serializeInt(playerId);
+ }
+
+ @Override
+ public IdentifiedEvent deserialize(Deserializer deserializer) throws SerializationException {
+ return new IdentifiedEvent(deserializer.deserializeInt());
+ }
+}
diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/PlayerJoinedRoomEvent.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/PlayerJoinedRoomEvent.java
new file mode 100644
index 0000000..f9389a3
--- /dev/null
+++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/PlayerJoinedRoomEvent.java
@@ -0,0 +1,35 @@
+package kz.ilotterytea.frogartha.domain.events;
+
+import com.github.czyzby.websocket.serialization.SerializationException;
+import com.github.czyzby.websocket.serialization.Transferable;
+import com.github.czyzby.websocket.serialization.impl.Deserializer;
+import com.github.czyzby.websocket.serialization.impl.Serializer;
+import kz.ilotterytea.frogartha.domain.PlayerData;
+
+public class PlayerJoinedRoomEvent extends Event implements Transferable<PlayerJoinedRoomEvent> {
+ private PlayerData data;
+
+ public PlayerJoinedRoomEvent() {
+ }
+
+ public PlayerJoinedRoomEvent(int playerId, PlayerData data) {
+ super(playerId);
+ this.data = data;
+ }
+
+ public PlayerData getData() {
+ return data;
+ }
+
+ @Override
+ public void serialize(Serializer serializer) throws SerializationException {
+ serializer
+ .serializeInt(playerId)
+ .serializeTransferable(data);
+ }
+
+ @Override
+ public PlayerJoinedRoomEvent deserialize(Deserializer deserializer) throws SerializationException {
+ return new PlayerJoinedRoomEvent(deserializer.deserializeInt(), deserializer.deserializeTransferable(new PlayerData()));
+ }
+}
diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/PlayerLeftRoomEvent.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/PlayerLeftRoomEvent.java
new file mode 100644
index 0000000..5472e95
--- /dev/null
+++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/PlayerLeftRoomEvent.java
@@ -0,0 +1,25 @@
+package kz.ilotterytea.frogartha.domain.events;
+
+import com.github.czyzby.websocket.serialization.SerializationException;
+import com.github.czyzby.websocket.serialization.Transferable;
+import com.github.czyzby.websocket.serialization.impl.Deserializer;
+import com.github.czyzby.websocket.serialization.impl.Serializer;
+
+public class PlayerLeftRoomEvent extends Event implements Transferable<PlayerLeftRoomEvent> {
+ public PlayerLeftRoomEvent() {
+ }
+
+ public PlayerLeftRoomEvent(int playerId) {
+ super(playerId);
+ }
+
+ @Override
+ public void serialize(Serializer serializer) throws SerializationException {
+ serializer.serializeInt(playerId);
+ }
+
+ @Override
+ public PlayerLeftRoomEvent deserialize(Deserializer deserializer) throws SerializationException {
+ return new PlayerLeftRoomEvent(deserializer.deserializeInt());
+ }
+}
diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/SenderJoinedRoomEvent.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/SenderJoinedRoomEvent.java
new file mode 100644
index 0000000..b032c47
--- /dev/null
+++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/SenderJoinedRoomEvent.java
@@ -0,0 +1,51 @@
+package kz.ilotterytea.frogartha.domain.events;
+
+import com.github.czyzby.websocket.serialization.SerializationException;
+import com.github.czyzby.websocket.serialization.Transferable;
+import com.github.czyzby.websocket.serialization.impl.Deserializer;
+import com.github.czyzby.websocket.serialization.impl.Serializer;
+import kz.ilotterytea.frogartha.domain.PlayerData;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class SenderJoinedRoomEvent extends Event implements Transferable<SenderJoinedRoomEvent> {
+ private List<Integer> ids;
+ private List<PlayerData> players;
+
+ public SenderJoinedRoomEvent() {
+ }
+
+ public SenderJoinedRoomEvent(int playerId, List<Integer> ids, List<PlayerData> players) {
+ super(playerId);
+ this.ids = ids;
+ this.players = players;
+ }
+
+ public List<Integer> getIds() {
+ return ids;
+ }
+
+ public List<PlayerData> getPlayers() {
+ return players;
+ }
+
+ @Override
+ public void serialize(Serializer serializer) throws SerializationException {
+ serializer.serializeInt(playerId)
+ .serializeIntArray(ids.stream().mapToInt(Integer::intValue).toArray())
+ .serializeTransferableArray(players.toArray(new PlayerData[]{}));
+ }
+
+ @Override
+ public SenderJoinedRoomEvent deserialize(Deserializer deserializer) throws SerializationException {
+ List<Integer> ids = Arrays.stream(deserializer.deserializeIntArray()).boxed().collect(Collectors.toList());
+ return new SenderJoinedRoomEvent(
+ deserializer.deserializeInt(),
+ new ArrayList<>(ids),
+ new ArrayList<>(Arrays.asList(deserializer.deserializeTransferableArray(new PlayerData(), size -> new PlayerData[ids.size()])))
+ );
+ }
+}
diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/SenderLeftRoomEvent.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/SenderLeftRoomEvent.java
new file mode 100644
index 0000000..2c2b35b
--- /dev/null
+++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/SenderLeftRoomEvent.java
@@ -0,0 +1,25 @@
+package kz.ilotterytea.frogartha.domain.events;
+
+import com.github.czyzby.websocket.serialization.SerializationException;
+import com.github.czyzby.websocket.serialization.Transferable;
+import com.github.czyzby.websocket.serialization.impl.Deserializer;
+import com.github.czyzby.websocket.serialization.impl.Serializer;
+
+public class SenderLeftRoomEvent extends Event implements Transferable<SenderLeftRoomEvent> {
+ public SenderLeftRoomEvent() {
+ }
+
+ public SenderLeftRoomEvent(int playerId) {
+ super(playerId);
+ }
+
+ @Override
+ public void serialize(Serializer serializer) throws SerializationException {
+ serializer.serializeInt(playerId);
+ }
+
+ @Override
+ public SenderLeftRoomEvent deserialize(Deserializer deserializer) throws SerializationException {
+ return new SenderLeftRoomEvent(deserializer.deserializeInt());
+ }
+}
diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/server/Acknowledge.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/server/Acknowledge.java
deleted file mode 100644
index 8ca0f66..0000000
--- a/shared/src/main/java/kz/ilotterytea/frogartha/domain/server/Acknowledge.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package kz.ilotterytea.frogartha.domain.server;
-
-import com.github.czyzby.websocket.serialization.SerializationException;
-import com.github.czyzby.websocket.serialization.Transferable;
-import com.github.czyzby.websocket.serialization.impl.Deserializer;
-import com.github.czyzby.websocket.serialization.impl.Serializer;
-
-public class Acknowledge implements Transferable<Acknowledge> {
- public enum AcknowledgeCode {
- IDENTIFIED
- }
-
- private AcknowledgeCode code;
-
- public Acknowledge() {
- }
-
- public Acknowledge(AcknowledgeCode code) {
- this.code = code;
- }
-
- public AcknowledgeCode getCode() {
- return code;
- }
-
- @Override
- public String toString() {
- return "Acknowledge{" +
- "code=" + code.toString() +
- '}';
- }
-
- @Override
- public void serialize(Serializer serializer) throws SerializationException {
- serializer.serializeInt(code.ordinal());
- }
-
- @Override
- public Acknowledge deserialize(Deserializer deserializer) throws SerializationException {
- return new Acknowledge(AcknowledgeCode.values()[deserializer.deserializeInt()]);
- }
-}
diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/exceptions/PlayerKickException.java b/shared/src/main/java/kz/ilotterytea/frogartha/exceptions/PlayerKickException.java
index ec0deb4..ad9c408 100644
--- a/shared/src/main/java/kz/ilotterytea/frogartha/exceptions/PlayerKickException.java
+++ b/shared/src/main/java/kz/ilotterytea/frogartha/exceptions/PlayerKickException.java
@@ -25,6 +25,14 @@ public class PlayerKickException extends RuntimeException implements Transferabl
return new PlayerKickException("Kicked for jump spamming");
}
+ public static PlayerKickException illegalOperation() {
+ return new PlayerKickException("Illegal operation");
+ }
+
+ public static PlayerKickException notInRoom() {
+ return new PlayerKickException("You are not in room");
+ }
+
@Override
public void serialize(Serializer serializer) throws SerializationException {
serializer.serializeString(getMessage());
diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/utils/SerializerUtils.java b/shared/src/main/java/kz/ilotterytea/frogartha/utils/SerializerUtils.java
index 2df2acf..e005937 100644
--- a/shared/src/main/java/kz/ilotterytea/frogartha/utils/SerializerUtils.java
+++ b/shared/src/main/java/kz/ilotterytea/frogartha/utils/SerializerUtils.java
@@ -3,20 +3,28 @@ package kz.ilotterytea.frogartha.utils;
import com.github.czyzby.websocket.serialization.impl.ManualSerializer;
import kz.ilotterytea.frogartha.domain.Identity;
import kz.ilotterytea.frogartha.domain.actions.ChangedDirectionAction;
+import kz.ilotterytea.frogartha.domain.actions.JoinRoomAction;
+import kz.ilotterytea.frogartha.domain.actions.LeaveRoomAction;
import kz.ilotterytea.frogartha.domain.actions.PlayerJumpAction;
-import kz.ilotterytea.frogartha.domain.events.ChangedDirectionEvent;
-import kz.ilotterytea.frogartha.domain.events.PlayerJumpEvent;
-import kz.ilotterytea.frogartha.domain.server.Acknowledge;
+import kz.ilotterytea.frogartha.domain.events.*;
import kz.ilotterytea.frogartha.exceptions.PlayerKickException;
public class SerializerUtils {
public static void registerTypes(ManualSerializer serializer) {
- serializer.register(new Acknowledge());
serializer.register(new Identity());
serializer.register(new PlayerKickException());
serializer.register(new PlayerJumpAction());
serializer.register(new PlayerJumpEvent());
serializer.register(new ChangedDirectionAction());
serializer.register(new ChangedDirectionEvent());
+ serializer.register(new IdentifiedEvent());
+
+ serializer.register(new JoinRoomAction());
+ serializer.register(new PlayerJoinedRoomEvent());
+ serializer.register(new SenderJoinedRoomEvent());
+
+ serializer.register(new LeaveRoomAction());
+ serializer.register(new PlayerLeftRoomEvent());
+ serializer.register(new SenderLeftRoomEvent());
}
}