Added chat, improved player input responses, and rebalanced weapons.
This commit is contained in:
parent
bf0982fbd9
commit
e909b90457
|
@ -1,7 +1,13 @@
|
|||
.idea/
|
||||
target/
|
||||
client-builds/
|
||||
client.yaml
|
||||
server.yaml
|
||||
|
||||
# Ignore the ./config directory so that developers can put their config files
|
||||
# there for server and client apps.
|
||||
config
|
||||
|
||||
# Ignore compiled tool executables
|
||||
build-clients
|
||||
setversion
|
||||
|
|
47
README.md
47
README.md
|
@ -8,45 +8,22 @@ _Read this guide to get started and join a server in just a minute or two!_
|
|||
|
||||
1. Make sure you've got at least Java 17 installed. You can get it [here](https://adoptium.net/temurin/releases).
|
||||
2. Download the `aos2-client` JAR file from the [releases page](https://github.com/andrewlalis/ace-of-shades-2/releases) that's compatible with your system.
|
||||
3. Run the game by double-clicking the JAR file, or entering `java -jar <jarfile>` in a terminal. This should generate a `config.yaml` file.
|
||||
3. Run the game by double-clicking the JAR file, or entering `java -jar <jarfile>` in a terminal. This should generate a `client.yaml` file.
|
||||
4. Set the `serverHost`, `serverPort`, and `username` properties accordingly for the server you want to join.
|
||||
5. Run the game again to join the server and start playing!
|
||||
|
||||
### Controls
|
||||
- `WASD` to move, `SPACE` to jump, `LEFT-CONTROL` to crouch.
|
||||
- `LEFT-CLICK` to use your held item (shoot, destroy blocks, etc.).
|
||||
- `RIGHT-CLICK` to interact with things using your held item (place blocks, etc.).
|
||||
- `R` to reload.
|
||||
- `T` to chat. Press `ENTER` to send the chat.
|
||||
- `ESCAPE` to exit the game.
|
||||
- Numbers are used for selecting different items.
|
||||
- `F3` toggles showing debug info.
|
||||
|
||||
## Setting up a Server
|
||||
Setting up a server is quite easy. Just go to the [releases page](https://github.com/andrewlalis/ace-of-shades-2/releases) and download the latest `aos2-server` JAR file. Similar to the client, it's best if you provide a `config.yaml` file to the server, in the same directory. The following snippet shows the structure and default values of a server's configuration.
|
||||
```yaml
|
||||
port: 25565
|
||||
connectionBacklog: 5
|
||||
ticksPerSecond: 20.0
|
||||
world: worlds.redfort
|
||||
teams:
|
||||
- name: Red
|
||||
color: [0.8, 0, 0]
|
||||
spawnPoint: A
|
||||
- name: Blue
|
||||
color: [0, 0, 0.8]
|
||||
spawnPoint: B
|
||||
physics:
|
||||
gravity: 29.43
|
||||
walkingSpeed: 4
|
||||
crouchingSpeed: 1.5
|
||||
sprintingSpeed: 9
|
||||
movementAcceleration: 2
|
||||
movementDeceleration: 1
|
||||
jumpVerticalSpeed: 8
|
||||
actions:
|
||||
blockBreakCooldown: 0.25
|
||||
blockPlaceCooldown: 0.1
|
||||
blockBreakReach: 5
|
||||
blockPlaceReach: 5
|
||||
blockBulletDamageResistance: 3
|
||||
blockBulletDamageCooldown: 10
|
||||
resupplyCooldown: 30
|
||||
resupplyRadius: 3
|
||||
teamSpawnProtection: 10
|
||||
movementAccuracyDecreaseFactor: 0.01
|
||||
friendlyFire: false
|
||||
```
|
||||
Setting up a server is quite easy. Just go to the [releases page](https://github.com/andrewlalis/ace-of-shades-2/releases) and download the latest `aos2-server` JAR file, and run it. It'll create a `server.yaml` configuration file if you don't provide one.
|
||||
|
||||
## Configuration
|
||||
Both the client and server use a similar style of YAML-based configuration, where upon booting up, the program will look for a configuration file in the current working directory with one of the following names: `configuration`, `config`, `cfg`, ending in either `.yaml` or `.yml`. Alternatively, you can provide the path to a configuration file at a different location via a single command-line argument. For example:
|
||||
|
|
|
@ -83,14 +83,7 @@ public class Client implements Runnable {
|
|||
return;
|
||||
}
|
||||
|
||||
gameRenderer = new GameRenderer(this);
|
||||
gameRenderer.setupWindow(
|
||||
inputHandler,
|
||||
new PlayerViewCursorCallback(config.input, this, gameRenderer.getCamera(), communicationHandler),
|
||||
new PlayerInputKeyCallback(inputHandler),
|
||||
new PlayerInputMouseClickCallback(inputHandler),
|
||||
new PlayerInputMouseScrollCallback(this, communicationHandler)
|
||||
);
|
||||
gameRenderer = new GameRenderer(this, inputHandler);
|
||||
soundManager = new SoundManager();
|
||||
log.debug("Sound system initialized.");
|
||||
|
||||
|
@ -207,6 +200,13 @@ public class Client implements Runnable {
|
|||
if (soundManager != null) {
|
||||
soundManager.play("chat", 1, myPlayer.getEyePosition(), myPlayer.getVelocity());
|
||||
}
|
||||
} else if (msg instanceof ClientOrientationUpdateMessage orientationUpdateMessage) {
|
||||
runLater(() -> {
|
||||
myPlayer.setOrientation(orientationUpdateMessage.x(), orientationUpdateMessage.y());
|
||||
if (gameRenderer != null) {
|
||||
gameRenderer.getCamera().setOrientationToPlayer(myPlayer);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,6 +222,10 @@ public class Client implements Runnable {
|
|||
return inputHandler;
|
||||
}
|
||||
|
||||
public CommunicationHandler getCommunicationHandler() {
|
||||
return communicationHandler;
|
||||
}
|
||||
|
||||
public Map<Integer, Team> getTeams() {
|
||||
return teams;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import nl.andrewl.aos2_client.model.ClientPlayer;
|
|||
import nl.andrewl.aos_core.model.item.BlockItemStack;
|
||||
import nl.andrewl.aos_core.model.world.Hit;
|
||||
import nl.andrewl.aos_core.net.client.BlockColorMessage;
|
||||
import nl.andrewl.aos_core.net.client.ChatWrittenMessage;
|
||||
import nl.andrewl.aos_core.net.client.ClientInputState;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
|
@ -35,6 +36,9 @@ public class InputHandler {
|
|||
|
||||
private boolean debugEnabled;
|
||||
|
||||
private boolean chatting;
|
||||
private StringBuffer chatText = new StringBuffer();
|
||||
|
||||
|
||||
public InputHandler(Client client, CommunicationHandler comm) {
|
||||
this.client = client;
|
||||
|
@ -66,6 +70,7 @@ public class InputHandler {
|
|||
}
|
||||
|
||||
public void setForward(boolean forward) {
|
||||
if (chatting) return;
|
||||
this.forward = forward;
|
||||
updateInputState();
|
||||
}
|
||||
|
@ -75,6 +80,7 @@ public class InputHandler {
|
|||
}
|
||||
|
||||
public void setBackward(boolean backward) {
|
||||
if (chatting) return;
|
||||
this.backward = backward;
|
||||
updateInputState();
|
||||
}
|
||||
|
@ -84,6 +90,7 @@ public class InputHandler {
|
|||
}
|
||||
|
||||
public void setLeft(boolean left) {
|
||||
if (chatting) return;
|
||||
this.left = left;
|
||||
updateInputState();
|
||||
}
|
||||
|
@ -93,6 +100,7 @@ public class InputHandler {
|
|||
}
|
||||
|
||||
public void setRight(boolean right) {
|
||||
if (chatting) return;
|
||||
this.right = right;
|
||||
updateInputState();
|
||||
}
|
||||
|
@ -102,6 +110,7 @@ public class InputHandler {
|
|||
}
|
||||
|
||||
public void setJumping(boolean jumping) {
|
||||
if (chatting) return;
|
||||
this.jumping = jumping;
|
||||
updateInputState();
|
||||
}
|
||||
|
@ -111,6 +120,7 @@ public class InputHandler {
|
|||
}
|
||||
|
||||
public void setCrouching(boolean crouching) {
|
||||
if (chatting) return;
|
||||
this.crouching = crouching;
|
||||
updateInputState();
|
||||
}
|
||||
|
@ -120,6 +130,7 @@ public class InputHandler {
|
|||
}
|
||||
|
||||
public void setSprinting(boolean sprinting) {
|
||||
if (chatting) return;
|
||||
this.sprinting = sprinting;
|
||||
updateInputState();
|
||||
}
|
||||
|
@ -129,6 +140,7 @@ public class InputHandler {
|
|||
}
|
||||
|
||||
public void setHitting(boolean hitting) {
|
||||
if (chatting) return;
|
||||
this.hitting = hitting;
|
||||
updateInputState();
|
||||
}
|
||||
|
@ -138,6 +150,7 @@ public class InputHandler {
|
|||
}
|
||||
|
||||
public void setInteracting(boolean interacting) {
|
||||
if (chatting) return;
|
||||
this.interacting = interacting;
|
||||
updateInputState();
|
||||
}
|
||||
|
@ -147,6 +160,7 @@ public class InputHandler {
|
|||
}
|
||||
|
||||
public void setReloading(boolean reloading) {
|
||||
if (chatting) return;
|
||||
this.reloading = reloading;
|
||||
updateInputState();
|
||||
}
|
||||
|
@ -156,6 +170,7 @@ public class InputHandler {
|
|||
}
|
||||
|
||||
public void setSelectedInventoryIndex(int selectedInventoryIndex) {
|
||||
if (chatting) return;
|
||||
this.selectedInventoryIndex = selectedInventoryIndex;
|
||||
updateInputState();
|
||||
}
|
||||
|
@ -168,6 +183,57 @@ public class InputHandler {
|
|||
this.debugEnabled = !debugEnabled;
|
||||
}
|
||||
|
||||
public void enableChatting() {
|
||||
if (chatting) return;
|
||||
setForward(false);
|
||||
setBackward(false);
|
||||
setLeft(false);
|
||||
setRight(false);
|
||||
setJumping(false);
|
||||
setCrouching(false);
|
||||
setSprinting(false);
|
||||
setReloading(false);
|
||||
chatting = true;
|
||||
chatText = new StringBuffer();
|
||||
}
|
||||
|
||||
public boolean isChatting() {
|
||||
return chatting;
|
||||
}
|
||||
|
||||
public void cancelChatting() {
|
||||
chatting = false;
|
||||
chatText.delete(0, chatText.length());
|
||||
}
|
||||
|
||||
public void appendToChat(int codePoint) {
|
||||
if (!chatting || chatText.length() + 1 > 120) return;
|
||||
chatText.appendCodePoint(codePoint);
|
||||
}
|
||||
|
||||
public void appendToChat(String s) {
|
||||
if (!chatting || chatText.length() + s.length() > 120) return;
|
||||
chatText.append(s);
|
||||
}
|
||||
|
||||
public void deleteFromChat() {
|
||||
if (!chatting || chatText.length() == 0) return;
|
||||
chatText.deleteCharAt(chatText.length() - 1);
|
||||
}
|
||||
|
||||
public String getChatText() {
|
||||
return chatText.toString();
|
||||
}
|
||||
|
||||
public void sendChat() {
|
||||
if (!chatting) return;
|
||||
String text = chatText.toString().trim();
|
||||
cancelChatting();
|
||||
if (!text.isBlank()) {
|
||||
client.getCommunicationHandler().sendMessage(new ChatWrittenMessage(text));
|
||||
}
|
||||
}
|
||||
|
||||
public void pickBlock() {
|
||||
var player = client.getMyPlayer();
|
||||
if (player.getInventory().getSelectedItemStack() instanceof BlockItemStack stack) {
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package nl.andrewl.aos2_client.control;
|
||||
|
||||
import org.lwjgl.glfw.GLFWCharCallbackI;
|
||||
|
||||
public class PlayerCharacterInputCallback implements GLFWCharCallbackI {
|
||||
private final InputHandler inputHandler;
|
||||
|
||||
public PlayerCharacterInputCallback(InputHandler inputHandler) {
|
||||
this.inputHandler = inputHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(long window, int codepoint) {
|
||||
if (inputHandler.isChatting()) {
|
||||
inputHandler.appendToChat(codepoint);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,12 +24,23 @@ public class PlayerInputKeyCallback implements GLFWKeyCallbackI {
|
|||
case GLFW_KEY_LEFT_SHIFT -> inputHandler.setSprinting(true);
|
||||
case GLFW_KEY_R -> inputHandler.setReloading(true);
|
||||
|
||||
case GLFW_KEY_BACKSPACE -> inputHandler.deleteFromChat();
|
||||
case GLFW_KEY_ENTER -> inputHandler.sendChat();
|
||||
|
||||
case GLFW_KEY_1 -> inputHandler.setSelectedInventoryIndex(0);
|
||||
case GLFW_KEY_2 -> inputHandler.setSelectedInventoryIndex(1);
|
||||
case GLFW_KEY_3 -> inputHandler.setSelectedInventoryIndex(2);
|
||||
case GLFW_KEY_4 -> inputHandler.setSelectedInventoryIndex(3);
|
||||
|
||||
case GLFW_KEY_F3 -> inputHandler.toggleDebugEnabled();
|
||||
|
||||
case GLFW_KEY_ESCAPE -> {
|
||||
if (inputHandler.isChatting()) {
|
||||
inputHandler.cancelChatting();
|
||||
} else {
|
||||
glfwSetWindowShouldClose(window, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
switch (key) {
|
||||
|
@ -42,7 +53,15 @@ public class PlayerInputKeyCallback implements GLFWKeyCallbackI {
|
|||
case GLFW_KEY_LEFT_SHIFT -> inputHandler.setSprinting(false);
|
||||
case GLFW_KEY_R -> inputHandler.setReloading(false);
|
||||
|
||||
case GLFW_KEY_ESCAPE -> glfwSetWindowShouldClose(window, true);
|
||||
case GLFW_KEY_T -> inputHandler.enableChatting();
|
||||
case GLFW_KEY_SLASH -> {
|
||||
inputHandler.enableChatting();
|
||||
inputHandler.appendToChat("/");
|
||||
}
|
||||
}
|
||||
} else if (action == GLFW_REPEAT) {
|
||||
switch (key) {
|
||||
case GLFW_KEY_BACKSPACE -> inputHandler.deleteFromChat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ public class PlayerInputMouseScrollCallback implements GLFWScrollCallbackI {
|
|||
private final Client client;
|
||||
private final CommunicationHandler comm;
|
||||
|
||||
public PlayerInputMouseScrollCallback(Client client, CommunicationHandler comm) {
|
||||
public PlayerInputMouseScrollCallback(Client client) {
|
||||
this.client = client;
|
||||
this.comm = comm;
|
||||
this.comm = client.getCommunicationHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,11 +30,11 @@ public class PlayerViewCursorCallback implements GLFWCursorPosCallbackI {
|
|||
private float lastMouseCursorY;
|
||||
private long lastOrientationUpdateSentAt = 0L;
|
||||
|
||||
public PlayerViewCursorCallback(ClientConfig.InputConfig config, Client client, Camera cam, CommunicationHandler comm) {
|
||||
this.config = config;
|
||||
public PlayerViewCursorCallback(Client client, Camera cam) {
|
||||
this.config = client.getConfig().input;
|
||||
this.client = client;
|
||||
this.camera = cam;
|
||||
this.comm = comm;
|
||||
this.comm = client.getCommunicationHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,7 +3,7 @@ package nl.andrewl.aos2_client.render;
|
|||
import nl.andrewl.aos2_client.Camera;
|
||||
import nl.andrewl.aos2_client.Client;
|
||||
import nl.andrewl.aos2_client.config.ClientConfig;
|
||||
import nl.andrewl.aos2_client.control.InputHandler;
|
||||
import nl.andrewl.aos2_client.control.*;
|
||||
import nl.andrewl.aos2_client.model.ClientPlayer;
|
||||
import nl.andrewl.aos2_client.render.chunk.ChunkRenderer;
|
||||
import nl.andrewl.aos2_client.render.gui.GuiRenderer;
|
||||
|
@ -36,42 +36,36 @@ public class GameRenderer {
|
|||
private static final float Z_FAR = 500f;
|
||||
|
||||
private final ClientConfig.DisplayConfig config;
|
||||
private ChunkRenderer chunkRenderer;
|
||||
private GuiRenderer guiRenderer;
|
||||
private ModelRenderer modelRenderer;
|
||||
private final ChunkRenderer chunkRenderer;
|
||||
private final GuiRenderer guiRenderer;
|
||||
private final ModelRenderer modelRenderer;
|
||||
private final Camera camera;
|
||||
private final Client client;
|
||||
|
||||
// Standard models for various game components.
|
||||
private Model playerModel;
|
||||
private Model rifleModel;
|
||||
private Model blockModel;
|
||||
private Model bulletModel;
|
||||
private Model smgModel;
|
||||
private Model shotgunModel;
|
||||
private Model flagModel;
|
||||
private final Model playerModel;
|
||||
private final Model rifleModel;
|
||||
private final Model blockModel;
|
||||
private final Model bulletModel;
|
||||
private final Model smgModel;
|
||||
private final Model shotgunModel;
|
||||
private final Model flagModel;
|
||||
|
||||
private long windowHandle;
|
||||
private int screenWidth = 800;
|
||||
private int screenHeight = 600;
|
||||
private final long windowHandle;
|
||||
private final int screenWidth;
|
||||
private final int screenHeight;
|
||||
|
||||
private final Matrix4f perspectiveTransform;
|
||||
|
||||
public GameRenderer(Client client) {
|
||||
public GameRenderer(Client client, InputHandler inputHandler) {
|
||||
this.config = client.getConfig().display;
|
||||
this.client = client;
|
||||
this.camera = new Camera();
|
||||
camera.setToPlayer(client.getMyPlayer());
|
||||
this.perspectiveTransform = new Matrix4f();
|
||||
}
|
||||
|
||||
public void setupWindow(
|
||||
InputHandler inputHandler,
|
||||
GLFWCursorPosCallbackI viewCursorCallback,
|
||||
GLFWKeyCallbackI inputKeyCallback,
|
||||
GLFWMouseButtonCallbackI mouseButtonCallback,
|
||||
GLFWScrollCallbackI scrollCallback
|
||||
) {
|
||||
// Initialize window!
|
||||
|
||||
GLFWErrorCallback.createPrint(System.err).set();
|
||||
if (!glfwInit()) throw new IllegalStateException("Could not initialize GLFW.");
|
||||
glfwDefaultWindowHints();
|
||||
|
@ -96,10 +90,11 @@ public class GameRenderer {
|
|||
log.debug("Initialized GLFW window.");
|
||||
|
||||
// Setup callbacks.
|
||||
glfwSetKeyCallback(windowHandle, inputKeyCallback);
|
||||
glfwSetCursorPosCallback(windowHandle, viewCursorCallback);
|
||||
glfwSetMouseButtonCallback(windowHandle, mouseButtonCallback);
|
||||
glfwSetScrollCallback(windowHandle, scrollCallback);
|
||||
glfwSetKeyCallback(windowHandle, new PlayerInputKeyCallback(inputHandler));
|
||||
glfwSetCursorPosCallback(windowHandle, new PlayerViewCursorCallback(client, camera));
|
||||
glfwSetMouseButtonCallback(windowHandle, new PlayerInputMouseClickCallback(inputHandler));
|
||||
glfwSetScrollCallback(windowHandle, new PlayerInputMouseScrollCallback(client));
|
||||
glfwSetCharCallback(windowHandle, new PlayerCharacterInputCallback(inputHandler));
|
||||
if (config.captureCursor) {
|
||||
glfwSetInputMode(windowHandle, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||
}
|
||||
|
@ -282,15 +277,15 @@ public class GameRenderer {
|
|||
}
|
||||
|
||||
public void freeWindow() {
|
||||
if (rifleModel != null) rifleModel.free();
|
||||
if (smgModel != null) smgModel.free();
|
||||
if (flagModel != null) flagModel.free();
|
||||
if (bulletModel != null) bulletModel.free();
|
||||
if (playerModel != null) playerModel.free();
|
||||
if (blockModel != null) blockModel.free();
|
||||
if (modelRenderer != null) modelRenderer.free();
|
||||
if (guiRenderer != null) guiRenderer.free();
|
||||
if (chunkRenderer != null) chunkRenderer.free();
|
||||
rifleModel.free();
|
||||
smgModel.free();
|
||||
flagModel.free();
|
||||
bulletModel.free();
|
||||
playerModel.free();
|
||||
blockModel.free();
|
||||
modelRenderer.free();
|
||||
guiRenderer.free();
|
||||
chunkRenderer.free();
|
||||
GL.destroy();
|
||||
Callbacks.glfwFreeCallbacks(windowHandle);
|
||||
glfwSetErrorCallback(null);
|
||||
|
|
|
@ -223,7 +223,7 @@ public class GuiRenderer {
|
|||
nvgSave(vgId);
|
||||
|
||||
drawCrosshair(width, height);
|
||||
drawChat(width, height, client.getChat());
|
||||
drawChat(width, height, client);
|
||||
drawHealthBar(width, height, client.getMyPlayer());
|
||||
drawHeldItemStackInfo(width, height, client.getMyPlayer());
|
||||
if (client.getInputHandler().isDebugEnabled()) {
|
||||
|
@ -269,18 +269,18 @@ public class GuiRenderer {
|
|||
private void drawHealthBar(float w, float h, ClientPlayer player) {
|
||||
nvgFillColor(vgId, GuiUtils.rgba(1, 0, 0, 1, colorA));
|
||||
nvgBeginPath(vgId);
|
||||
nvgRect(vgId, 20, h - 60, 100, 20);
|
||||
nvgRect(vgId, w - 170, h - 110, 100, 20);
|
||||
nvgFill(vgId);
|
||||
nvgFillColor(vgId, GuiUtils.rgba(0, 1, 0, 1, colorA));
|
||||
nvgBeginPath(vgId);
|
||||
nvgRect(vgId, 20, h - 60, 100 * player.getHealth(), 20);
|
||||
nvgRect(vgId, w - 170, h - 110, 100 * player.getHealth(), 20);
|
||||
nvgFill(vgId);
|
||||
|
||||
nvgFillColor(vgId, GuiUtils.rgba(1, 1, 1, 1, colorA));
|
||||
nvgFontSize(vgId, 12f);
|
||||
nvgFontFaceId(vgId, jetbrainsMonoFont);
|
||||
nvgTextAlign(vgId, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
|
||||
nvgText(vgId, 20, h - 30, String.format("%.2f / 1.00 HP", player.getHealth()));
|
||||
nvgText(vgId, w - 170, h - 80, String.format("%.2f / 1.00 HP", player.getHealth()));
|
||||
}
|
||||
|
||||
private void drawHeldItemStackInfo(float w, float h, ClientPlayer player) {
|
||||
|
@ -324,19 +324,20 @@ public class GuiRenderer {
|
|||
nvgText(vgId, w - 140, h - 14, String.format("Selected value: %d", stack.getSelectedValue()));
|
||||
}
|
||||
|
||||
private void drawChat(float w, float h, Chat chat) {
|
||||
private void drawChat(float w, float h, Client client) {
|
||||
float chatWidth = w / 3;
|
||||
float chatHeight = h / 4;
|
||||
|
||||
nvgFillColor(vgId, GuiUtils.rgba(0, 0, 0, 0.25f, colorA));
|
||||
nvgBeginPath(vgId);
|
||||
nvgRect(vgId, 0, 0, chatWidth, chatHeight);
|
||||
nvgRect(vgId, 0, h - chatHeight - 16, chatWidth, chatHeight);
|
||||
nvgFill(vgId);
|
||||
|
||||
var chat = client.getChat();
|
||||
nvgFontSize(vgId, 12f);
|
||||
nvgFontFaceId(vgId, jetbrainsMonoFont);
|
||||
nvgTextAlign(vgId, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
|
||||
float y = chatHeight - 12;
|
||||
float y = h - 16 - 12;
|
||||
for (var msg : chat.getMessages()) {
|
||||
if (msg.author().equals("_ANNOUNCE")) {
|
||||
nvgFillColor(vgId, GuiUtils.rgba(0.7f, 0, 0, 1, colorA));
|
||||
|
@ -348,9 +349,17 @@ public class GuiRenderer {
|
|||
nvgFillColor(vgId, GuiUtils.rgba(1, 1, 1, 1, colorA));
|
||||
nvgText(vgId, 5, y, msg.author() + ": " + msg.message());
|
||||
}
|
||||
|
||||
y -= 16;
|
||||
}
|
||||
var input = client.getInputHandler();
|
||||
if (input.isChatting()) {
|
||||
nvgFillColor(vgId, GuiUtils.rgba(0, 0, 0, 0.5f, colorA));
|
||||
nvgBeginPath(vgId);
|
||||
nvgRect(vgId, 0, h - 16, w, 16);
|
||||
nvgFill(vgId);
|
||||
nvgFillColor(vgId, GuiUtils.rgba(1, 1, 1, 1, colorA));
|
||||
nvgText(vgId, 5, h - 14, "> " + input.getChatText() + "_");
|
||||
}
|
||||
}
|
||||
|
||||
private void drawDebugInfo(float w, float h, Client client) {
|
||||
|
|
|
@ -48,6 +48,7 @@ public final class Net {
|
|||
serializer.registerType(19, BlockColorMessage.class);
|
||||
serializer.registerType(20, ChatMessage.class);
|
||||
serializer.registerType(21, ChatWrittenMessage.class);
|
||||
serializer.registerType(22, ClientOrientationUpdateMessage.class);
|
||||
}
|
||||
|
||||
public static ExtendedDataInputStream getInputStream(InputStream in) {
|
||||
|
|
|
@ -14,7 +14,7 @@ public class Ak47 extends Gun {
|
|||
0.1f,
|
||||
1.2f,
|
||||
0.4f,
|
||||
30f,
|
||||
0.1f,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,14 +7,14 @@ public class Rifle extends Gun {
|
|||
super(
|
||||
id,
|
||||
"Rifle",
|
||||
5,
|
||||
6,
|
||||
8,
|
||||
1,
|
||||
0.97f,
|
||||
0.98f,
|
||||
0.8f,
|
||||
2.5f,
|
||||
0.8f,
|
||||
50f,
|
||||
0.2f,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,14 +7,14 @@ public class Winchester extends Gun {
|
|||
super(
|
||||
id,
|
||||
"Winchester",
|
||||
10,
|
||||
6,
|
||||
4,
|
||||
4,
|
||||
0.85f,
|
||||
0.75f,
|
||||
2.5f,
|
||||
0.3f,
|
||||
60f,
|
||||
0.33f,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,6 @@ appender.console.name = STDOUT
|
|||
appender.console.layout.type = PatternLayout
|
||||
appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
|
||||
|
||||
rootLogger.level = debug
|
||||
rootLogger.level = info
|
||||
rootLogger.appenderRefs = stdout
|
||||
rootLogger.appenderRef.stdout.ref = STDOUT
|
|
@ -7,6 +7,8 @@ import nl.andrewl.aos_core.model.item.ItemStack;
|
|||
import nl.andrewl.aos_core.model.world.Chunk;
|
||||
import nl.andrewl.aos_core.model.world.WorldIO;
|
||||
import nl.andrewl.aos_core.net.TcpReceiver;
|
||||
import nl.andrewl.aos_core.net.client.ChatMessage;
|
||||
import nl.andrewl.aos_core.net.client.ChatWrittenMessage;
|
||||
import nl.andrewl.aos_core.net.connect.ConnectAcceptMessage;
|
||||
import nl.andrewl.aos_core.net.connect.ConnectRejectMessage;
|
||||
import nl.andrewl.aos_core.net.connect.ConnectRequestMessage;
|
||||
|
@ -77,6 +79,25 @@ public class ClientCommunicationHandler {
|
|||
if (chunk != null && hashMessage.hash() != chunk.blockHash()) {
|
||||
sendTcpMessage(new ChunkDataMessage(chunk));
|
||||
}
|
||||
} else if (msg instanceof ChatWrittenMessage chatWrittenMessage) {
|
||||
if (chatWrittenMessage.message().startsWith("/t ")) {
|
||||
if (player.getTeam() != null) {
|
||||
var chat = new ChatMessage(
|
||||
System.currentTimeMillis(),
|
||||
player.getUsername(),
|
||||
chatWrittenMessage.message().substring(3)
|
||||
);
|
||||
for (var teamPlayer : server.getTeamManager().getPlayers(player.getTeam())) {
|
||||
server.getPlayerManager().getHandler(teamPlayer).sendTcpMessage(chat);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
server.getPlayerManager().broadcastTcpMessage(new ChatMessage(
|
||||
System.currentTimeMillis(),
|
||||
player.getUsername(),
|
||||
chatWrittenMessage.message()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,6 +131,10 @@ public class ClientCommunicationHandler {
|
|||
log.debug("Sent connect accept message.");
|
||||
sendInitialData();
|
||||
log.debug("Sent initial data.");
|
||||
sendTcpMessage(ChatMessage.privateMessage("Welcome to the server, " + player.getUsername() + "."));
|
||||
if (player.getTeam() != null) {
|
||||
sendTcpMessage(ChatMessage.privateMessage("You've joined the " + player.getTeam().getName() + " team."));
|
||||
}
|
||||
// Initiate a TCP receiver thread to accept incoming messages from the client.
|
||||
TcpReceiver tcpReceiver = new TcpReceiver(in, this::handleTcpMessage)
|
||||
.withShutdownHook(() -> server.getPlayerManager().deregister(this.player));
|
||||
|
@ -135,10 +160,12 @@ public class ClientCommunicationHandler {
|
|||
|
||||
public void sendTcpMessage(Message msg) {
|
||||
ForkJoinPool.commonPool().submit(() -> {
|
||||
try {
|
||||
Net.write(msg, out);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
synchronized (out) {
|
||||
try {
|
||||
Net.write(msg, out);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -111,6 +111,16 @@ public class PlayerActionManager {
|
|||
gunNeedsReCock = true;
|
||||
}
|
||||
server.getPlayerManager().getHandler(player.getId()).sendDatagramPacket(new ItemStackMessage(player.getInventory()));
|
||||
// Apply recoil!
|
||||
float recoilFactor = 10f; // Maximum number of degrees to recoil.
|
||||
float recoil = recoilFactor * gun.getRecoil() + (float) ThreadLocalRandom.current().nextGaussian(0, 0.01);
|
||||
player.getOrientation().y += Math.toRadians(recoil);
|
||||
server.getPlayerManager().getHandler(player.getId()).sendDatagramPacket(new ClientOrientationUpdateMessage(
|
||||
player.getOrientation().x(),
|
||||
player.getOrientation().y()
|
||||
));
|
||||
server.getPlayerManager().broadcastUdpMessageToAllBut(player.getUpdateMessage(now), player);
|
||||
// Play sound!
|
||||
String shotSound = null;
|
||||
if (gun instanceof Rifle) {
|
||||
shotSound = "shot_m1-garand_1";
|
||||
|
|
|
@ -2,6 +2,11 @@ package nl.andrewl.aos2_server.logic;
|
|||
|
||||
import nl.andrewl.aos_core.net.client.ClientInputState;
|
||||
|
||||
/**
|
||||
* Component that keeps track of any impulses the player has made since the
|
||||
* last tick. This way, if a player activates an input for even a fraction of
|
||||
* a tick, it'll register.
|
||||
*/
|
||||
public class PlayerImpulses {
|
||||
public boolean forward;
|
||||
public boolean backward;
|
||||
|
|
Loading…
Reference in New Issue