diff options
15 files changed, 307 insertions, 28 deletions
diff --git a/core/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java b/core/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java deleted file mode 100644 index f80948a..0000000 --- a/core/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java +++ /dev/null @@ -1,7 +0,0 @@ -package kz.ilotterytea.frogartha; - -public class FrogarthaConstants { - public static class URLS { - public static String SESSION_WSS = "ws://localhost:20015"; - } -} 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 da100fa..76f7f4c 100644 --- a/core/src/main/java/kz/ilotterytea/frogartha/entities/PlayerEntity.java +++ b/core/src/main/java/kz/ilotterytea/frogartha/entities/PlayerEntity.java @@ -4,23 +4,34 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Camera; import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.math.collision.Ray; +import kz.ilotterytea.frogartha.FrogarthaConstants; +import kz.ilotterytea.frogartha.FrogarthaGame; +import kz.ilotterytea.frogartha.domain.client.PlayerJumpAction; public class PlayerEntity extends RenderableEntity { + private final Vector3 startPosition, endPosition; private final Camera camera; - private final float velocity; + + private float jumpStrength, elapsedTime; + private boolean isJumpKeyPressed, isJumping, lockJump; public PlayerEntity(Camera camera) { super(new Texture(Gdx.files.internal("sprites/player/player.png"))); this.camera = camera; - this.velocity = 8f; + this.endPosition = Vector3.Zero; + this.startPosition = Vector3.Zero; setCameraPosition(); } @Override public void update(float delta) { - updatePlayerPosition(); + if (!lockJump) handlePlayerJump(delta); + + if (isJumping) performJump(delta); + updatePlayerLook(); } @@ -30,27 +41,38 @@ public class PlayerEntity extends RenderableEntity { setCameraPosition(); } - private void updatePlayerPosition() { - float xMovement = 0f, zMovement = 0f; + private void handlePlayerJump(float delta) { + int jumpKey = Input.Keys.SPACE; - if (Gdx.input.isKeyPressed(Input.Keys.W)) { - xMovement = -1f; - } else if (Gdx.input.isKeyPressed(Input.Keys.S)) { - xMovement = 1f; + if (Gdx.input.isKeyPressed(jumpKey)) { + isJumpKeyPressed = true; + setJumpStrength(jumpStrength + delta); + } else if (isJumpKeyPressed) { + isJumpKeyPressed = false; + lockJump = true; + FrogarthaGame.getInstance().getSessionClient().send(new PlayerJumpAction(jumpStrength)); } + } - if (Gdx.input.isKeyPressed(Input.Keys.A)) { - zMovement = 1f; - } else if (Gdx.input.isKeyPressed(Input.Keys.D)) { - zMovement = -1f; - } + private void performJump(float delta) { + elapsedTime += delta; - xMovement *= velocity / 100f; - zMovement *= velocity / 100f; + float t = elapsedTime / jumpStrength; - setPosition(position.x + xMovement, position.y, position.z + zMovement); + float x = MathUtils.lerp(startPosition.x, endPosition.x, t); + float z = MathUtils.lerp(startPosition.z, endPosition.z, t); - if (xMovement != 0f || zMovement != 0f) setCameraPosition(); + float y = FrogarthaConstants.Player.MAX_JUMP_HEIGHT - 4 * FrogarthaConstants.Player.MAX_JUMP_HEIGHT * (t - 0.5f) * (t - 0.5f); + setPosition(x, y, z); + + if (elapsedTime >= jumpStrength) { + elapsedTime = 0f; + lockJump = false; + setStartPosition(Vector3.Zero); + setEndPosition(Vector3.Zero); + setJumping(false); + setJumpStrength(0f); + } } private void updatePlayerLook() { @@ -58,7 +80,7 @@ public class PlayerEntity extends RenderableEntity { Ray ray = camera.getPickRay(Gdx.input.getX(), Gdx.input.getY()); final float distance = -ray.origin.y / ray.direction.y; Vector3 point = new Vector3(ray.direction).scl(distance).add(ray.origin); - super.setDirection(point.x, 1f, point.z); + super.setDirection(point.x, position.y, point.z); } private void setCameraPosition() { @@ -68,4 +90,24 @@ public class PlayerEntity extends RenderableEntity { this.camera.lookAt(position); this.camera.update(); } + + public float getJumpStrength() { + return jumpStrength; + } + + public void setJumpStrength(float jumpStrength) { + this.jumpStrength = Math.min(jumpStrength, FrogarthaConstants.Player.MAX_JUMP_STRENGTH); + } + + public void setJumping(boolean jumping) { + isJumping = jumping; + } + + public void setStartPosition(Vector3 startPosition) { + this.startPosition.set(startPosition.x, startPosition.y, startPosition.z); + } + + public void setEndPosition(Vector3 endPosition) { + this.endPosition.set(endPosition.x, endPosition.y, endPosition.z); + } } 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 d8f9b36..24fc00c 100644 --- a/core/src/main/java/kz/ilotterytea/frogartha/screens/GameScreen.java +++ b/core/src/main/java/kz/ilotterytea/frogartha/screens/GameScreen.java @@ -125,4 +125,8 @@ public class GameScreen implements Screen { decalBatch = new DecalBatch(new CameraGroupStrategy(camera)); } + + public PlayerEntity getPlayerEntity() { + return playerEntity; + } } 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 c775e57..73dfd3c 100644 --- a/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionClient.java +++ b/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionClient.java @@ -9,6 +9,7 @@ import kz.ilotterytea.frogartha.FrogarthaConstants; import kz.ilotterytea.frogartha.FrogarthaGame; import kz.ilotterytea.frogartha.domain.Identity; import kz.ilotterytea.frogartha.domain.server.Acknowledge; +import kz.ilotterytea.frogartha.events.PlayerJumpEvent; import kz.ilotterytea.frogartha.exceptions.PlayerKickException; import kz.ilotterytea.frogartha.utils.Logger; import kz.ilotterytea.frogartha.utils.SerializerUtils; @@ -60,6 +61,7 @@ public class SessionClient implements WebSocketListener { } if (obj instanceof Acknowledge) SessionHandlers.handleAcknowledge((Acknowledge) obj); + else if (obj instanceof PlayerJumpEvent) SessionHandlers.handlePlayerJumpEvent((PlayerJumpEvent) obj); else if (obj instanceof PlayerKickException) throw (PlayerKickException) obj; } catch (PlayerKickException e) { log.log("Kicked out: {}", e.getMessage()); 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 383640b..c4d4237 100644 --- a/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionHandlers.java +++ b/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionHandlers.java @@ -2,6 +2,9 @@ package kz.ilotterytea.frogartha.sessions; import kz.ilotterytea.frogartha.FrogarthaGame; import kz.ilotterytea.frogartha.domain.server.Acknowledge; +import kz.ilotterytea.frogartha.entities.PlayerEntity; +import kz.ilotterytea.frogartha.events.PlayerJumpEvent; +import kz.ilotterytea.frogartha.screens.GameScreen; import kz.ilotterytea.frogartha.utils.Logger; public class SessionHandlers { @@ -16,4 +19,19 @@ public class SessionHandlers { game.getIdentityClient().setAuthorized(true); } } + + public static void handlePlayerJumpEvent(PlayerJumpEvent event) { + if (!game.getScreen().getClass().equals(GameScreen.class)) { + log.log("The screen is not GameScreen, but the session received PlayerJumpEvent"); + return; + } + + GameScreen screen = (GameScreen) game.getScreen(); + PlayerEntity entity = screen.getPlayerEntity(); + + entity.setJumpStrength(event.getJumpStrength()); + entity.setStartPosition(event.getStartPosition()); + entity.setEndPosition(event.getEndPosition()); + entity.setJumping(true); + } } 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 e25dffd..c141bd9 100644 --- a/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java +++ b/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java @@ -2,6 +2,7 @@ package kz.ilotterytea.frogartha.server; import com.github.czyzby.websocket.serialization.impl.ManualSerializer; import kz.ilotterytea.frogartha.domain.Identity; +import kz.ilotterytea.frogartha.domain.client.PlayerJumpAction; import kz.ilotterytea.frogartha.exceptions.PlayerKickException; import kz.ilotterytea.frogartha.utils.Logger; import kz.ilotterytea.frogartha.utils.SerializerUtils; @@ -76,8 +77,13 @@ public class FrogarthaServer extends WebSocketServer { throw PlayerKickException.internalServerError(); } - if (obj instanceof Identity) ServerHandlers.handleIdentity(player, (Identity) obj); - else throw PlayerKickException.internalServerError(); + if (obj instanceof Identity) { + ServerHandlers.handleIdentity(player, (Identity) obj); + } else if (obj instanceof PlayerJumpAction) { + ServerHandlers.handlePlayerJumpAction(player, (PlayerJumpAction) obj); + } else { + throw PlayerKickException.internalServerError(); + } } catch (PlayerKickException e) { kickConnection(player, e); } catch (Exception e) { 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 d9326a6..8744e58 100644 --- a/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java +++ b/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java @@ -1,6 +1,7 @@ package kz.ilotterytea.frogartha.server; import kz.ilotterytea.frogartha.domain.Identity; +import kz.ilotterytea.frogartha.domain.PlayerState; import org.java_websocket.WebSocket; import java.sql.Timestamp; @@ -11,6 +12,7 @@ public class PlayerConnection { private final int id; private final WebSocket connection; private Identity identity; + private PlayerState state; private final Timestamp connectedTimestamp; @@ -21,6 +23,7 @@ public class PlayerConnection { this.connectedTimestamp = new Timestamp(System.currentTimeMillis()); this.identity = null; + this.state = null; } public void send(Object object) { @@ -50,6 +53,11 @@ public class PlayerConnection { public void setIdentity(Identity identity) { this.identity = identity; + if (state == null) state = new PlayerState(); + } + + public PlayerState getState() { + return state; } @Override 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 b50392f..44162ae 100644 --- a/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java +++ b/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java @@ -1,7 +1,12 @@ package kz.ilotterytea.frogartha.server; +import com.badlogic.gdx.math.Vector3; +import kz.ilotterytea.frogartha.FrogarthaConstants; import kz.ilotterytea.frogartha.domain.Identity; +import kz.ilotterytea.frogartha.domain.PlayerState; +import kz.ilotterytea.frogartha.domain.client.PlayerJumpAction; import kz.ilotterytea.frogartha.domain.server.Acknowledge; +import kz.ilotterytea.frogartha.events.PlayerJumpEvent; import kz.ilotterytea.frogartha.exceptions.PlayerKickException; import kz.ilotterytea.frogartha.utils.Logger; @@ -22,4 +27,36 @@ public class ServerHandlers { player.send(new Acknowledge(Acknowledge.AcknowledgeCode.IDENTIFIED)); log.log("Successfully identified {} for {}", identity, player); } + + public static void handlePlayerJumpAction(PlayerConnection player, PlayerJumpAction action) { + PlayerState state = player.getState(); + + float nowTimestamp = System.currentTimeMillis() / 1000f; + + if (state.getNextJumpTimestamp() > nowTimestamp) { + throw PlayerKickException.jumpSpam(); + } + + state.setNextJumpTimestamp(nowTimestamp + action.getJumpStrength()); + + // calculating start and end positions + Vector3 position = state.getPosition(); + Vector3 startPosition = position.cpy(); + + float jumpDistance = action.getJumpStrength() * FrogarthaConstants.Player.JUMP_SPEED; + Vector3 d = new Vector3(state.getDirection()).sub(startPosition).nor(); + + Vector3 endPosition = new Vector3( + position.x + d.x * jumpDistance, + position.y, + position.z + d.z * jumpDistance + ); + + state.setPosition(endPosition.x, endPosition.y, endPosition.z); + + player.send(new PlayerJumpEvent( + player.getId(), startPosition, endPosition, action.getJumpStrength() + )); + log.log("{} jumped from {} to {} with strength {}", player, startPosition, endPosition, action.getJumpStrength()); + } } diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java b/shared/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java new file mode 100644 index 0000000..d5cdb06 --- /dev/null +++ b/shared/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java @@ -0,0 +1,13 @@ +package kz.ilotterytea.frogartha; + +public class FrogarthaConstants { + public static class URLS { + public static final String SESSION_WSS = "ws://localhost:20015"; + } + + public static class Player { + public static final float MAX_JUMP_STRENGTH = 1.5f; + public static final float MAX_JUMP_HEIGHT = 2f; + public static final float JUMP_SPEED = 10f; + } +} diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/PlayerState.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/PlayerState.java new file mode 100644 index 0000000..15ba015 --- /dev/null +++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/PlayerState.java @@ -0,0 +1,42 @@ +package kz.ilotterytea.frogartha.domain; + +import com.badlogic.gdx.math.Vector3; + +public class PlayerState { + private final Vector3 position, direction; + private float nextJumpTimestamp; + + public PlayerState() { + this(new Vector3(), new Vector3()); + } + + public PlayerState(Vector3 position, Vector3 direction) { + this.position = position; + this.direction = direction; + this.nextJumpTimestamp = 0; + } + + public Vector3 getPosition() { + return position; + } + + public void setPosition(float x, float y, float z) { + this.position.set(x, y, z); + } + + public Vector3 getDirection() { + return direction; + } + + public float getNextJumpTimestamp() { + return nextJumpTimestamp; + } + + public void setNextJumpTimestamp(float nextJumpTimestamp) { + this.nextJumpTimestamp = nextJumpTimestamp; + } + + public void setDirection(float x, float y, float z) { + this.position.set(x, y, z); + } +} diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/client/PlayerJumpAction.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/client/PlayerJumpAction.java new file mode 100644 index 0000000..272f514 --- /dev/null +++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/client/PlayerJumpAction.java @@ -0,0 +1,32 @@ +package kz.ilotterytea.frogartha.domain.client; + +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.FrogarthaConstants; + +public class PlayerJumpAction implements Transferable<PlayerJumpAction> { + private float jumpStrength; + + public PlayerJumpAction() { + } + + public PlayerJumpAction(Float jumpStrength) { + this.jumpStrength = Math.min(jumpStrength, FrogarthaConstants.Player.MAX_JUMP_STRENGTH); + } + + public float getJumpStrength() { + return jumpStrength; + } + + @Override + public void serialize(Serializer serializer) throws SerializationException { + serializer.serializeFloat(jumpStrength); + } + + @Override + public PlayerJumpAction deserialize(Deserializer deserializer) throws SerializationException { + return new PlayerJumpAction(deserializer.deserializeFloat()); + } +} diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/events/Event.java b/shared/src/main/java/kz/ilotterytea/frogartha/events/Event.java new file mode 100644 index 0000000..dcc0177 --- /dev/null +++ b/shared/src/main/java/kz/ilotterytea/frogartha/events/Event.java @@ -0,0 +1,16 @@ +package kz.ilotterytea.frogartha.events; + +public class Event { + protected int playerId; + + public Event() { + } + + public Event(int playerId) { + this.playerId = playerId; + } + + public int getPlayerId() { + return playerId; + } +} diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/events/PlayerJumpEvent.java b/shared/src/main/java/kz/ilotterytea/frogartha/events/PlayerJumpEvent.java new file mode 100644 index 0000000..a084555 --- /dev/null +++ b/shared/src/main/java/kz/ilotterytea/frogartha/events/PlayerJumpEvent.java @@ -0,0 +1,58 @@ +package kz.ilotterytea.frogartha.events; + +import com.badlogic.gdx.math.Vector3; +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 PlayerJumpEvent extends Event implements Transferable<PlayerJumpEvent> { + private Vector3 startPosition, endPosition; + private float jumpStrength; + + public PlayerJumpEvent() { + super(); + } + + public PlayerJumpEvent(Integer playerId, Vector3 startPosition, Vector3 endPosition, Float jumpStrength) { + super(playerId); + this.startPosition = startPosition; + this.endPosition = endPosition; + this.jumpStrength = jumpStrength; + } + + public Vector3 getStartPosition() { + return startPosition; + } + + public Vector3 getEndPosition() { + return endPosition; + } + + public float getJumpStrength() { + return jumpStrength; + } + + @Override + public void serialize(Serializer serializer) throws SerializationException { + serializer + // id + .serializeInt(playerId) + // start position + .serializeFloatArray(new float[]{startPosition.x, startPosition.y, startPosition.z}) + // end position + .serializeFloatArray(new float[]{endPosition.x, endPosition.y, endPosition.z}) + // jump strength + .serializeFloat(jumpStrength); + } + + @Override + public PlayerJumpEvent deserialize(Deserializer deserializer) throws SerializationException { + return new PlayerJumpEvent( + deserializer.deserializeInt(), + new Vector3(deserializer.deserializeFloatArray()), + new Vector3(deserializer.deserializeFloatArray()), + deserializer.deserializeFloat() + ); + } +} 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 4eaf389..ec0deb4 100644 --- a/shared/src/main/java/kz/ilotterytea/frogartha/exceptions/PlayerKickException.java +++ b/shared/src/main/java/kz/ilotterytea/frogartha/exceptions/PlayerKickException.java @@ -21,6 +21,10 @@ public class PlayerKickException extends RuntimeException implements Transferabl return new PlayerKickException("Internal Server Error"); } + public static PlayerKickException jumpSpam() { + return new PlayerKickException("Kicked for jump spamming"); + } + @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 bf0c3f3..1c62e0d 100644 --- a/shared/src/main/java/kz/ilotterytea/frogartha/utils/SerializerUtils.java +++ b/shared/src/main/java/kz/ilotterytea/frogartha/utils/SerializerUtils.java @@ -2,7 +2,9 @@ package kz.ilotterytea.frogartha.utils; import com.github.czyzby.websocket.serialization.impl.ManualSerializer; import kz.ilotterytea.frogartha.domain.Identity; +import kz.ilotterytea.frogartha.domain.client.PlayerJumpAction; import kz.ilotterytea.frogartha.domain.server.Acknowledge; +import kz.ilotterytea.frogartha.events.PlayerJumpEvent; import kz.ilotterytea.frogartha.exceptions.PlayerKickException; public class SerializerUtils { @@ -10,5 +12,7 @@ public class SerializerUtils { serializer.register(new Acknowledge()); serializer.register(new Identity()); serializer.register(new PlayerKickException()); + serializer.register(new PlayerJumpAction()); + serializer.register(new PlayerJumpEvent()); } } |
