summaryrefslogtreecommitdiff
path: root/server/src
diff options
context:
space:
mode:
authorilotterytea <iltsu@alright.party>2025-01-22 04:11:41 +0500
committerilotterytea <iltsu@alright.party>2025-01-22 04:11:41 +0500
commit449c70cbf900a80042f70dd8929f302f0f0016d7 (patch)
treecd958299e1a421165c370cb31500315f0635560c /server/src
parentb96a6d7005fcb90a21aeb21ddebe8bb7b82a7ef5 (diff)
feat: MULTIPLAYER!!!!!!!!!!!!!!! LETS FUCKING GOOOOOOOO!!!!!
Diffstat (limited to 'server/src')
-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
4 files changed, 169 insertions, 6 deletions
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);
}
}