Added better block color picking, smg and flag models, and implemented gun accuracy.

This commit is contained in:
Andrew Lalis 2022-07-26 16:22:22 +02:00
parent cefaeae5f6
commit 0f31f32607
14 changed files with 103 additions and 20 deletions

View File

@ -1,10 +1,7 @@
package nl.andrewl.aos2_client; package nl.andrewl.aos2_client;
import nl.andrewl.aos2_client.config.ClientConfig; 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.control.PlayerInputKeyCallback;
import nl.andrewl.aos2_client.control.PlayerInputMouseClickCallback;
import nl.andrewl.aos2_client.control.PlayerViewCursorCallback;
import nl.andrewl.aos2_client.model.ClientPlayer; import nl.andrewl.aos2_client.model.ClientPlayer;
import nl.andrewl.aos2_client.model.OtherPlayer; import nl.andrewl.aos2_client.model.OtherPlayer;
import nl.andrewl.aos2_client.render.GameRenderer; import nl.andrewl.aos2_client.render.GameRenderer;
@ -84,7 +81,8 @@ public class Client implements Runnable {
gameRenderer.setupWindow( gameRenderer.setupWindow(
new PlayerViewCursorCallback(config.input, this, gameRenderer.getCamera(), communicationHandler), new PlayerViewCursorCallback(config.input, this, gameRenderer.getCamera(), communicationHandler),
new PlayerInputKeyCallback(inputHandler), new PlayerInputKeyCallback(inputHandler),
new PlayerInputMouseClickCallback(inputHandler) new PlayerInputMouseClickCallback(inputHandler),
new PlayerInputMouseScrollCallback(this, communicationHandler)
); );
soundManager = new SoundManager(); soundManager = new SoundManager();
log.debug("Sound system initialized."); log.debug("Sound system initialized.");

View File

@ -13,7 +13,7 @@ public class ClientConfig {
public static class DisplayConfig { public static class DisplayConfig {
public boolean fullscreen = false; public boolean fullscreen = false;
public boolean captureCursor = true; public boolean captureCursor = false;
public float fov = 70; public float fov = 70;
} }
} }

View File

@ -1,8 +1,12 @@
package nl.andrewl.aos2_client.control; package nl.andrewl.aos2_client.control;
import nl.andrewl.aos2_client.CommunicationHandler;
import nl.andrewl.aos_core.net.client.ClientInputState;
import nl.andrewl.aos2_client.Client; import nl.andrewl.aos2_client.Client;
import nl.andrewl.aos2_client.CommunicationHandler;
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.ClientInputState;
import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.glfw.GLFW.*;
@ -46,5 +50,19 @@ public class InputHandler {
comm.sendDatagramPacket(currentInputState); comm.sendDatagramPacket(currentInputState);
lastInputState = currentInputState; lastInputState = currentInputState;
} }
ClientPlayer player = client.getMyPlayer();
// Check for "pick block" functionality.
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_3) == GLFW_PRESS && player.getInventory().getSelectedItemStack() instanceof BlockItemStack stack) {
Hit hit = client.getWorld().getLookingAtPos(player.getEyePosition(), player.getViewVector(), 50);
if (hit != null) {
byte selectedBlock = client.getWorld().getBlockAt(hit.pos().x, hit.pos().y, hit.pos().z);
if (selectedBlock > 0) {
stack.setSelectedValue(selectedBlock);
comm.sendDatagramPacket(new BlockColorMessage(player.getId(), selectedBlock));
}
}
}
} }
} }

View File

@ -0,0 +1,30 @@
package nl.andrewl.aos2_client.control;
import nl.andrewl.aos2_client.Client;
import nl.andrewl.aos2_client.CommunicationHandler;
import nl.andrewl.aos_core.model.item.BlockItemStack;
import nl.andrewl.aos_core.net.client.BlockColorMessage;
import org.lwjgl.glfw.GLFWScrollCallbackI;
public class PlayerInputMouseScrollCallback implements GLFWScrollCallbackI {
private final Client client;
private final CommunicationHandler comm;
public PlayerInputMouseScrollCallback(Client client, CommunicationHandler comm) {
this.client = client;
this.comm = comm;
}
@Override
public void invoke(long window, double xoffset, double yoffset) {
System.out.println(yoffset);
if (client.getMyPlayer().getInventory().getSelectedItemStack() instanceof BlockItemStack stack) {
if (yoffset < 0) {
stack.setSelectedValue((byte) (stack.getSelectedValue() - 1));
} else if (yoffset > 0) {
stack.setSelectedValue((byte) (stack.getSelectedValue() + 1));
}
comm.sendDatagramPacket(new BlockColorMessage(client.getMyPlayer().getId(), stack.getSelectedValue()));
}
}
}

View File

@ -77,7 +77,8 @@ public class GameRenderer {
public void setupWindow( public void setupWindow(
GLFWCursorPosCallbackI viewCursorCallback, GLFWCursorPosCallbackI viewCursorCallback,
GLFWKeyCallbackI inputKeyCallback, GLFWKeyCallbackI inputKeyCallback,
GLFWMouseButtonCallbackI mouseButtonCallback GLFWMouseButtonCallbackI mouseButtonCallback,
GLFWScrollCallbackI scrollCallback
) { ) {
GLFWErrorCallback.createPrint(System.err).set(); GLFWErrorCallback.createPrint(System.err).set();
if (!glfwInit()) throw new IllegalStateException("Could not initialize GLFW."); if (!glfwInit()) throw new IllegalStateException("Could not initialize GLFW.");
@ -105,6 +106,7 @@ public class GameRenderer {
glfwSetKeyCallback(windowHandle, inputKeyCallback); glfwSetKeyCallback(windowHandle, inputKeyCallback);
glfwSetCursorPosCallback(windowHandle, viewCursorCallback); glfwSetCursorPosCallback(windowHandle, viewCursorCallback);
glfwSetMouseButtonCallback(windowHandle, mouseButtonCallback); glfwSetMouseButtonCallback(windowHandle, mouseButtonCallback);
glfwSetScrollCallback(windowHandle, scrollCallback);
if (config.captureCursor) { if (config.captureCursor) {
glfwSetInputMode(windowHandle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(windowHandle, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
} }

View File

@ -45,6 +45,7 @@ public final class Net {
serializer.registerType(16, SoundMessage.class); serializer.registerType(16, SoundMessage.class);
serializer.registerType(17, ProjectileMessage.class); serializer.registerType(17, ProjectileMessage.class);
serializer.registerType(18, ClientHealthMessage.class); serializer.registerType(18, ClientHealthMessage.class);
serializer.registerType(19, BlockColorMessage.class);
} }
public static ExtendedDataInputStream getInputStream(InputStream in) { public static ExtendedDataInputStream getInputStream(InputStream in) {

View File

@ -0,0 +1,13 @@
package nl.andrewl.aos_core.net.client;
import nl.andrewl.record_net.Message;
/**
* A message that's sent when a client is holding a block item stack, and
* selects a different color. It's also sent to other clients to tell them that
* the player with the given id has selected a different block color.
*/
public record BlockColorMessage(
int clientId,
byte block
) implements Message {}

BIN
design/models/flag.blend Normal file

Binary file not shown.

BIN
design/models/flag.blend1 Normal file

Binary file not shown.

BIN
design/models/smg.blend Normal file

Binary file not shown.

View File

@ -5,6 +5,7 @@ import nl.andrewl.aos2_server.model.ServerProjectile;
import nl.andrewl.aos_core.Directions; import nl.andrewl.aos_core.Directions;
import nl.andrewl.aos_core.model.Player; import nl.andrewl.aos_core.model.Player;
import nl.andrewl.aos_core.model.Projectile; import nl.andrewl.aos_core.model.Projectile;
import nl.andrewl.aos_core.model.item.Gun;
import nl.andrewl.aos_core.model.world.Hit; import nl.andrewl.aos_core.model.world.Hit;
import nl.andrewl.aos_core.net.client.ClientHealthMessage; import nl.andrewl.aos_core.net.client.ClientHealthMessage;
import nl.andrewl.aos_core.net.client.SoundMessage; import nl.andrewl.aos_core.net.client.SoundMessage;
@ -12,10 +13,7 @@ import nl.andrewl.aos_core.net.world.ChunkUpdateMessage;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.joml.Vector3f; import org.joml.Vector3f;
import java.util.HashMap; import java.util.*;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
/** /**
@ -36,18 +34,30 @@ public class ProjectileManager {
this.removalQueue = new LinkedList<>(); this.removalQueue = new LinkedList<>();
} }
public void spawnBullet(ServerPlayer player) { public void spawnBullet(ServerPlayer player, Gun gun) {
int id = nextProjectileId++; int id = nextProjectileId++;
if (nextProjectileId == Integer.MAX_VALUE) nextProjectileId = 1; if (nextProjectileId == Integer.MAX_VALUE) nextProjectileId = 1;
Random rand = ThreadLocalRandom.current();
Vector3f pos = new Vector3f(); Vector3f pos = new Vector3f();
Matrix4f bulletTransform = new Matrix4f() Matrix4f bulletTransform = new Matrix4f()
.translate(player.getEyePosition()) .translate(player.getEyePosition())
.rotate(player.getOrientation().x + (float) Math.PI, Directions.UPf) .rotate(player.getOrientation().x + (float) Math.PI, Directions.UPf)
.translate(-0.35f, -0.4f, 0.35f); .translate(-0.35f, -0.4f, 0.35f);
bulletTransform.transformPosition(pos); bulletTransform.transformPosition(pos);
Vector3f vel = new Vector3f(player.getViewVector()).normalize()
Vector3f direction = new Vector3f(player.getViewVector()).normalize();
float accuracy = gun.getAccuracy();
accuracy -= server.getConfig().actions.movementAccuracyDecreaseFactor * player.getVelocity().length();
float perturbationFactor = (1 - accuracy) / 8;
direction.x += rand.nextGaussian(0, perturbationFactor);
direction.y += rand.nextGaussian(0, perturbationFactor);
direction.z += rand.nextGaussian(0, perturbationFactor);
Vector3f vel = new Vector3f(direction).normalize()
.mul(200 * MOVEMENT_FACTOR) .mul(200 * MOVEMENT_FACTOR)
.add(player.getVelocity()); .add(player.getVelocity());
ServerProjectile bullet = new ServerProjectile(id, pos, vel, Projectile.Type.BULLET, player); ServerProjectile bullet = new ServerProjectile(id, pos, vel, Projectile.Type.BULLET, player);
projectiles.put(bullet.getId(), bullet); projectiles.put(bullet.getId(), bullet);
server.getPlayerManager().broadcastUdpMessage(bullet.toMessage(false)); server.getPlayerManager().broadcastUdpMessage(bullet.toMessage(false));

View File

@ -5,9 +5,11 @@ import nl.andrewl.aos2_server.config.ServerConfig;
import nl.andrewl.aos2_server.logic.WorldUpdater; import nl.andrewl.aos2_server.logic.WorldUpdater;
import nl.andrewl.aos2_server.model.ServerPlayer; import nl.andrewl.aos2_server.model.ServerPlayer;
import nl.andrewl.aos_core.config.Config; import nl.andrewl.aos_core.config.Config;
import nl.andrewl.aos_core.model.item.BlockItemStack;
import nl.andrewl.aos_core.model.world.World; import nl.andrewl.aos_core.model.world.World;
import nl.andrewl.aos_core.model.world.Worlds; import nl.andrewl.aos_core.model.world.Worlds;
import nl.andrewl.aos_core.net.UdpReceiver; import nl.andrewl.aos_core.net.UdpReceiver;
import nl.andrewl.aos_core.net.client.BlockColorMessage;
import nl.andrewl.aos_core.net.client.ClientInputState; import nl.andrewl.aos_core.net.client.ClientInputState;
import nl.andrewl.aos_core.net.client.ClientOrientationState; import nl.andrewl.aos_core.net.client.ClientOrientationState;
import nl.andrewl.aos_core.net.connect.DatagramInit; import nl.andrewl.aos_core.net.connect.DatagramInit;
@ -103,6 +105,12 @@ public class Server implements Runnable {
player.setOrientation(orientationState.x(), orientationState.y()); player.setOrientation(orientationState.x(), orientationState.y());
playerManager.broadcastUdpMessageToAllBut(player.getUpdateMessage(now), player); playerManager.broadcastUdpMessageToAllBut(player.getUpdateMessage(now), player);
} }
} else if (msg instanceof BlockColorMessage blockColorMessage) {
ServerPlayer player = playerManager.getPlayer(blockColorMessage.clientId());
if (player != null && player.getInventory().getSelectedItemStack() instanceof BlockItemStack stack) {
stack.setSelectedValue(blockColorMessage.block());
playerManager.broadcastUdpMessageToAllBut(blockColorMessage, player);
}
} }
} }

View File

@ -18,9 +18,12 @@ public class ServerConfig {
} }
public static class ActionsConfig { public static class ActionsConfig {
public float blockRemoveCooldown = 0.25f; public float blockBreakCooldown = 0.25f;
public float blockPlaceCooldown = 0.1f; public float blockPlaceCooldown = 0.1f;
public float blockBreakReach = 5;
public float blockPlaceReach = 5;
public float resupplyCooldown = 30; public float resupplyCooldown = 30;
public float resupplyRadius = 3; public float resupplyRadius = 3;
public float movementAccuracyDecreaseFactor = 0.01f;
} }
} }

View File

@ -111,7 +111,7 @@ public class PlayerActionManager {
now - gunLastShotAt > gun.getShotCooldownTime() * 1000 && now - gunLastShotAt > gun.getShotCooldownTime() * 1000 &&
(gun.isAutomatic() || !gunNeedsReCock) (gun.isAutomatic() || !gunNeedsReCock)
) { ) {
server.getProjectileManager().spawnBullet(player); server.getProjectileManager().spawnBullet(player, gun);
g.setBulletCount(g.getBulletCount() - 1); g.setBulletCount(g.getBulletCount() - 1);
gunLastShotAt = now; gunLastShotAt = now;
if (!gun.isAutomatic()) { if (!gun.isAutomatic()) {
@ -159,9 +159,9 @@ public class PlayerActionManager {
if ( if (
lastInputState.hitting() && lastInputState.hitting() &&
stack.getAmount() < stack.getType().getMaxAmount() && stack.getAmount() < stack.getType().getMaxAmount() &&
now - lastBlockRemovedAt > server.getConfig().actions.blockRemoveCooldown * 1000 now - lastBlockRemovedAt > server.getConfig().actions.blockBreakCooldown * 1000
) { ) {
var hit = world.getLookingAtPos(player.getEyePosition(), player.getViewVector(), 10); var hit = world.getLookingAtPos(player.getEyePosition(), player.getViewVector(), server.getConfig().actions.blockBreakReach);
if (hit != null) { if (hit != null) {
world.setBlockAt(hit.pos().x, hit.pos().y, hit.pos().z, (byte) 0); world.setBlockAt(hit.pos().x, hit.pos().y, hit.pos().z, (byte) 0);
lastBlockRemovedAt = now; lastBlockRemovedAt = now;
@ -177,7 +177,7 @@ public class PlayerActionManager {
stack.getAmount() > 0 && stack.getAmount() > 0 &&
now - lastBlockPlacedAt > server.getConfig().actions.blockPlaceCooldown * 1000 now - lastBlockPlacedAt > server.getConfig().actions.blockPlaceCooldown * 1000
) { ) {
var hit = world.getLookingAtPos(player.getEyePosition(), player.getViewVector(), 10); var hit = world.getLookingAtPos(player.getEyePosition(), player.getViewVector(), server.getConfig().actions.blockPlaceReach);
if (hit != null) { if (hit != null) {
Vector3i placePos = new Vector3i(hit.pos()); Vector3i placePos = new Vector3i(hit.pos());
placePos.add(hit.norm()); placePos.add(hit.norm());