Added more logic for separate handling of creative/spectator modes.

This commit is contained in:
Andrew Lalis 2022-08-01 16:40:26 +02:00
parent dbb2e8a40f
commit 935cbd1393
9 changed files with 72 additions and 46 deletions

View File

@ -96,7 +96,7 @@ public class Client implements Runnable {
gameRenderer.getCamera().interpolatePosition(dt); gameRenderer.getCamera().interpolatePosition(dt);
interpolatePlayers(now, dt); interpolatePlayers(now, dt);
interpolateProjectiles(dt); interpolateProjectiles(dt);
soundManager.playWalkingSounds(myPlayer, now); soundManager.playWalkingSounds(myPlayer, world, now);
gameRenderer.draw(); gameRenderer.draw();
lastFrameAt = now; lastFrameAt = now;
@ -121,6 +121,7 @@ public class Client implements Runnable {
myPlayer.getPosition().set(playerUpdate.px(), playerUpdate.py(), playerUpdate.pz()); myPlayer.getPosition().set(playerUpdate.px(), playerUpdate.py(), playerUpdate.pz());
myPlayer.getVelocity().set(playerUpdate.vx(), playerUpdate.vy(), playerUpdate.vz()); myPlayer.getVelocity().set(playerUpdate.vx(), playerUpdate.vy(), playerUpdate.vz());
myPlayer.setCrouching(playerUpdate.crouching()); myPlayer.setCrouching(playerUpdate.crouching());
myPlayer.setMode(playerUpdate.mode());
if (gameRenderer != null) { if (gameRenderer != null) {
gameRenderer.getCamera().setToPlayer(myPlayer); gameRenderer.getCamera().setToPlayer(myPlayer);
} }
@ -138,7 +139,7 @@ public class Client implements Runnable {
} }
}); });
} else if (msg instanceof ClientInventoryMessage inventoryMessage) { } else if (msg instanceof ClientInventoryMessage inventoryMessage) {
myPlayer.setInventory(inventoryMessage.inv()); runLater(() -> myPlayer.setInventory(inventoryMessage.inv()));
} else if (msg instanceof InventorySelectedStackMessage selectedStackMessage) { } else if (msg instanceof InventorySelectedStackMessage selectedStackMessage) {
myPlayer.getInventory().setSelectedIndex(selectedStackMessage.index()); myPlayer.getInventory().setSelectedIndex(selectedStackMessage.index());
} else if (msg instanceof ItemStackMessage itemStackMessage) { } else if (msg instanceof ItemStackMessage itemStackMessage) {
@ -238,7 +239,7 @@ public class Client implements Runnable {
movement.set(player.getVelocity()).mul(dt); movement.set(player.getVelocity()).mul(dt);
player.getPosition().add(movement); player.getPosition().add(movement);
player.updateModelTransform(); player.updateModelTransform();
soundManager.playWalkingSounds(player, now); soundManager.playWalkingSounds(player, world, now);
} }
gameRenderer.getGuiRenderer().updateNamePlates(players.values()); gameRenderer.getGuiRenderer().updateNamePlates(players.values());
} }

View File

@ -11,11 +11,14 @@ import nl.andrewl.aos2_client.render.model.Model;
import nl.andrewl.aos_core.model.PlayerMode; import nl.andrewl.aos_core.model.PlayerMode;
import nl.andrewl.aos_core.model.Team; import nl.andrewl.aos_core.model.Team;
import nl.andrewl.aos_core.model.item.BlockItemStack; import nl.andrewl.aos_core.model.item.BlockItemStack;
import nl.andrewl.aos_core.model.item.Inventory;
import nl.andrewl.aos_core.model.item.ItemTypes; import nl.andrewl.aos_core.model.item.ItemTypes;
import org.joml.Matrix3f; import org.joml.Matrix3f;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.lwjgl.glfw.*; import org.lwjgl.glfw.Callbacks;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL;
import java.io.IOException; import java.io.IOException;
@ -173,6 +176,7 @@ public class GameRenderer {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
ClientPlayer myPlayer = client.getMyPlayer(); ClientPlayer myPlayer = client.getMyPlayer();
Inventory inv = myPlayer.getInventory();
if (inputHandler.isNormalContextActive() && inputHandler.getNormalContext().isScopeEnabled()) { if (inputHandler.isNormalContextActive() && inputHandler.getNormalContext().isScopeEnabled()) {
updatePerspective(15); updatePerspective(15);
} else { } else {
@ -199,7 +203,7 @@ public class GameRenderer {
// Render guns! // Render guns!
rifleModel.bind(); rifleModel.bind();
if (myPlayer.getInventory().getSelectedItemStack().getType().getId() == ItemTypes.RIFLE.getId()) { if (inv.getSelectedItemStack() != null && inv.getSelectedItemStack().getType().getId() == ItemTypes.RIFLE.getId()) {
modelRenderer.render(rifleModel, myPlayer.getHeldItemTransformData(), myPlayer.getHeldItemNormalTransformData()); modelRenderer.render(rifleModel, myPlayer.getHeldItemTransformData(), myPlayer.getHeldItemNormalTransformData());
} }
for (var player : client.getPlayers().values()) { for (var player : client.getPlayers().values()) {
@ -210,7 +214,7 @@ public class GameRenderer {
} }
rifleModel.unbind(); rifleModel.unbind();
smgModel.bind(); smgModel.bind();
if (myPlayer.getInventory().getSelectedItemStack().getType().getId() == ItemTypes.AK_47.getId()) { if (inv.getSelectedItemStack() != null && inv.getSelectedItemStack().getType().getId() == ItemTypes.AK_47.getId()) {
modelRenderer.render(smgModel, myPlayer.getHeldItemTransformData(), myPlayer.getHeldItemNormalTransformData()); modelRenderer.render(smgModel, myPlayer.getHeldItemTransformData(), myPlayer.getHeldItemNormalTransformData());
} }
for (var player : client.getPlayers().values()) { for (var player : client.getPlayers().values()) {
@ -221,7 +225,7 @@ public class GameRenderer {
} }
smgModel.unbind(); smgModel.unbind();
shotgunModel.bind(); shotgunModel.bind();
if (myPlayer.getInventory().getSelectedItemStack().getType().getId() == ItemTypes.WINCHESTER.getId()) { if (inv.getSelectedItemStack() != null && inv.getSelectedItemStack().getType().getId() == ItemTypes.WINCHESTER.getId()) {
modelRenderer.render(shotgunModel, myPlayer.getHeldItemTransformData(), myPlayer.getHeldItemNormalTransformData()); modelRenderer.render(shotgunModel, myPlayer.getHeldItemTransformData(), myPlayer.getHeldItemNormalTransformData());
} }
for (var player : client.getPlayers().values()) { for (var player : client.getPlayers().values()) {
@ -233,7 +237,7 @@ public class GameRenderer {
shotgunModel.unbind(); shotgunModel.unbind();
blockModel.bind(); blockModel.bind();
if (myPlayer.getInventory().getSelectedItemStack().getType().getId() == ItemTypes.BLOCK.getId()) { if (inv.getSelectedItemStack() != null && inv.getSelectedItemStack().getType().getId() == ItemTypes.BLOCK.getId()) {
BlockItemStack stack = (BlockItemStack) myPlayer.getInventory().getSelectedItemStack(); BlockItemStack stack = (BlockItemStack) myPlayer.getInventory().getSelectedItemStack();
modelRenderer.setAspectColor(client.getWorld().getPalette().getColor(stack.getSelectedValue())); modelRenderer.setAspectColor(client.getWorld().getPalette().getColor(stack.getSelectedValue()));
modelRenderer.render(blockModel, myPlayer.getHeldItemTransformData(), myPlayer.getHeldItemNormalTransformData()); modelRenderer.render(blockModel, myPlayer.getHeldItemTransformData(), myPlayer.getHeldItemNormalTransformData());

View File

@ -8,6 +8,7 @@ import nl.andrewl.aos2_client.render.ShaderProgram;
import nl.andrewl.aos2_client.sound.SoundSource; import nl.andrewl.aos2_client.sound.SoundSource;
import nl.andrewl.aos_core.FileUtils; import nl.andrewl.aos_core.FileUtils;
import nl.andrewl.aos_core.model.Player; import nl.andrewl.aos_core.model.Player;
import nl.andrewl.aos_core.model.PlayerMode;
import nl.andrewl.aos_core.model.item.BlockItem; import nl.andrewl.aos_core.model.item.BlockItem;
import nl.andrewl.aos_core.model.item.BlockItemStack; import nl.andrewl.aos_core.model.item.BlockItemStack;
import nl.andrewl.aos_core.model.item.Gun; import nl.andrewl.aos_core.model.item.Gun;
@ -196,10 +197,12 @@ public class GuiRenderer {
glUniform1i(namePlateTextureSamplerUniform, 0); glUniform1i(namePlateTextureSamplerUniform, 0);
glUniformMatrix4fv(namePlateViewTransformUniform, false, viewTransformData); glUniformMatrix4fv(namePlateViewTransformUniform, false, viewTransformData);
glUniformMatrix4fv(namePlatePerspectiveTransformUniform, false, perspectiveTransformData); glUniformMatrix4fv(namePlatePerspectiveTransformUniform, false, perspectiveTransformData);
// Show nameplates from farther away if we're in creative/spectator.
float nameplateRadius = myPlayer.getMode() == PlayerMode.NORMAL ? 50 : 200;
for (var entry : playerNamePlates.entrySet()) { for (var entry : playerNamePlates.entrySet()) {
OtherPlayer player = entry.getKey(); OtherPlayer player = entry.getKey();
// Skip rendering far-away nameplates. // There are some scenarios where we skip rendering the name.
if (player.getPosition().distance(myPlayer.getPosition()) > 50) continue; if (player.getPosition().distance(myPlayer.getPosition()) > nameplateRadius || player.getMode() == PlayerMode.SPECTATOR) continue;
GuiTexture texture = entry.getValue(); GuiTexture texture = entry.getValue();
float aspectRatio = (float) texture.getHeight() / (float) texture.getWidth(); float aspectRatio = (float) texture.getHeight() / (float) texture.getWidth();
transformMatrix.identity() transformMatrix.identity()
@ -223,11 +226,12 @@ public class GuiRenderer {
nvgSave(vgId); nvgSave(vgId);
boolean scopeEnabled = client.getInputHandler().getNormalContext().isScopeEnabled(); boolean scopeEnabled = client.getInputHandler().getNormalContext().isScopeEnabled();
PlayerMode mode = client.getMyPlayer().getMode();
drawCrosshair(width, height, scopeEnabled); drawCrosshair(width, height, scopeEnabled);
drawHeldItemStackInfo(width, height, client.getMyPlayer()); drawHeldItemStackInfo(width, height, client.getMyPlayer());
if (!scopeEnabled) { if (!scopeEnabled) {
drawChat(width, height, client); drawChat(width, height, client);
drawHealthBar(width, height, client.getMyPlayer()); if (mode == PlayerMode.NORMAL) drawHealthBar(width, height, client.getMyPlayer());
} }
if (client.getInputHandler().getNormalContext().isDebugEnabled()) { if (client.getInputHandler().getNormalContext().isDebugEnabled()) {
drawDebugInfo(width, height, client); drawDebugInfo(width, height, client);

View File

@ -1,6 +1,8 @@
package nl.andrewl.aos2_client.sound; package nl.andrewl.aos2_client.sound;
import nl.andrewl.aos_core.model.Player; import nl.andrewl.aos_core.model.Player;
import nl.andrewl.aos_core.model.PlayerMode;
import nl.andrewl.aos_core.model.world.World;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.lwjgl.openal.AL; import org.lwjgl.openal.AL;
import org.lwjgl.openal.ALC; import org.lwjgl.openal.ALC;
@ -115,8 +117,9 @@ public class SoundManager {
play(soundName, gain, position, new Vector3f(0, 0, 0)); play(soundName, gain, position, new Vector3f(0, 0, 0));
} }
public void playWalkingSounds(Player player, long now) { public void playWalkingSounds(Player player, World world, long now) {
if (player.getVelocity().length() <= 0) return; // Don't play sounds for players who are still, non-normal mode, or not on the ground.
if (player.getVelocity().length() <= 0 || player.getMode() != PlayerMode.NORMAL || !player.isGrounded(world)) return;
long lastSoundAt = lastPlayerWalkingSounds.computeIfAbsent(player, p -> 0L); long lastSoundAt = lastPlayerWalkingSounds.computeIfAbsent(player, p -> 0L);
long delay = 500; // Delay in ms between footfalls. long delay = 500; // Delay in ms between footfalls.
if (player.getVelocity().length() > 5) delay -= 150; if (player.getVelocity().length() > 5) delay -= 150;

View File

@ -31,6 +31,7 @@ public class Inventory {
} }
public ItemStack getSelectedItemStack() { public ItemStack getSelectedItemStack() {
if (itemStacks.isEmpty()) return null;
return itemStacks.get(selectedIndex); return itemStacks.get(selectedIndex);
} }
@ -62,4 +63,9 @@ public class Inventory {
} }
return 1; return 1;
} }
public void clear() {
itemStacks.clear();
selectedIndex = -1;
}
} }

View File

@ -4,10 +4,7 @@ import nl.andrewl.aos2_server.model.ServerPlayer;
import nl.andrewl.aos_core.Net; import nl.andrewl.aos_core.Net;
import nl.andrewl.aos_core.model.PlayerMode; import nl.andrewl.aos_core.model.PlayerMode;
import nl.andrewl.aos_core.model.Team; import nl.andrewl.aos_core.model.Team;
import nl.andrewl.aos_core.model.item.BlockItemStack; import nl.andrewl.aos_core.model.item.*;
import nl.andrewl.aos_core.model.item.Gun;
import nl.andrewl.aos_core.model.item.GunItemStack;
import nl.andrewl.aos_core.model.item.ItemStack;
import nl.andrewl.aos_core.net.client.*; import nl.andrewl.aos_core.net.client.*;
import nl.andrewl.aos_core.net.connect.DatagramInit; import nl.andrewl.aos_core.net.connect.DatagramInit;
import nl.andrewl.record_net.Message; import nl.andrewl.record_net.Message;
@ -47,7 +44,7 @@ public class PlayerManager {
joinMessage = username + " joined the game."; joinMessage = username + " joined the game.";
} }
player.setPosition(getBestSpawnPoint(player)); player.setPosition(getBestSpawnPoint(player));
player.setMode(PlayerMode.NORMAL); setMode(player, PlayerMode.NORMAL);
// Tell all other players that this one has joined. // Tell all other players that this one has joined.
broadcastTcpMessageToAllBut(new PlayerJoinMessage( broadcastTcpMessageToAllBut(new PlayerJoinMessage(
player.getId(), player.getUsername(), player.getTeam() == null ? -1 : player.getTeam().getId(), player.getId(), player.getUsername(), player.getTeam() == null ? -1 : player.getTeam().getId(),
@ -201,6 +198,19 @@ public class PlayerManager {
handler.sendTcpMessage(ChatMessage.privateMessage("You've been resupplied at your team base.")); handler.sendTcpMessage(ChatMessage.privateMessage("You've been resupplied at your team base."));
} }
public void setMode(ServerPlayer player, PlayerMode mode) {
player.setMode(mode);
var inv = player.getInventory();
inv.clear();
if (mode == PlayerMode.NORMAL || mode == PlayerMode.CREATIVE) {
inv.getItemStacks().add(new GunItemStack(ItemTypes.RIFLE));
inv.getItemStacks().add(new GunItemStack(ItemTypes.AK_47));
inv.getItemStacks().add(new GunItemStack(ItemTypes.WINCHESTER));
inv.getItemStacks().add(new BlockItemStack(ItemTypes.BLOCK, 50, (byte) 1));
inv.setSelectedIndex(0);
}
}
public void handleUdpInit(DatagramInit init, DatagramPacket packet) { public void handleUdpInit(DatagramInit init, DatagramPacket packet) {
var handler = getHandler(init.clientId()); var handler = getHandler(init.clientId());
if (handler != null) { if (handler != null) {

View File

@ -6,6 +6,7 @@ import nl.andrewl.aos2_server.cli.ingame.PlayerCommand;
import nl.andrewl.aos2_server.model.ServerPlayer; import nl.andrewl.aos2_server.model.ServerPlayer;
import nl.andrewl.aos_core.model.PlayerMode; import nl.andrewl.aos_core.model.PlayerMode;
import nl.andrewl.aos_core.net.client.ChatMessage; import nl.andrewl.aos_core.net.client.ChatMessage;
import nl.andrewl.aos_core.net.client.ClientInventoryMessage;
public class PlayerModeCommand implements PlayerCommand { public class PlayerModeCommand implements PlayerCommand {
@Override @Override
@ -17,7 +18,8 @@ public class PlayerModeCommand implements PlayerCommand {
String modeText = args[0].trim().toUpperCase(); String modeText = args[0].trim().toUpperCase();
try { try {
PlayerMode mode = PlayerMode.valueOf(modeText); PlayerMode mode = PlayerMode.valueOf(modeText);
player.setMode(mode); server.getPlayerManager().setMode(player, mode);
handler.sendTcpMessage(new ClientInventoryMessage(player.getInventory()));
server.getPlayerManager().broadcastUdpMessage(player.getUpdateMessage(System.currentTimeMillis())); server.getPlayerManager().broadcastUdpMessage(player.getUpdateMessage(System.currentTimeMillis()));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
handler.sendTcpMessage(ChatMessage.privateMessage("Invalid mode. Should be NORMAL, CREATIVE, or SPECTATOR.")); handler.sendTcpMessage(ChatMessage.privateMessage("Invalid mode. Should be NORMAL, CREATIVE, or SPECTATOR."));

View File

@ -65,27 +65,30 @@ public class PlayerActionManager {
public void tick(long now, float dt, World world, Server server) { public void tick(long now, float dt, World world, Server server) {
updated = false; // Reset the updated flag. This will be set to true if the player was updated in this tick. updated = false; // Reset the updated flag. This will be set to true if the player was updated in this tick.
if (player.getInventory().getSelectedIndex() != input.selectedInventoryIndex()) {
player.getInventory().setSelectedIndex(input.selectedInventoryIndex());
// Tell the client that their inventory slot has been updated properly.
server.getPlayerManager().getHandler(player.getId()).sendDatagramPacket(new InventorySelectedStackMessage(player.getInventory().getSelectedIndex()));
updated = true; // Tell everyone else that this player's selected item has changed.
}
ItemStack selectedStack = player.getInventory().getSelectedItemStack(); if (player.getMode() != PlayerMode.SPECTATOR) {
if (selectedStack instanceof BlockItemStack b) { if (player.getInventory().getSelectedIndex() != input.selectedInventoryIndex()) {
tickBlockAction(now, server, world, b); player.getInventory().setSelectedIndex(input.selectedInventoryIndex());
} else if (selectedStack instanceof GunItemStack g) { // Tell the client that their inventory slot has been updated properly.
tickGunAction(now, server, g); server.getPlayerManager().getHandler(player.getId()).sendDatagramPacket(new InventorySelectedStackMessage(player.getInventory().getSelectedIndex()));
} updated = true; // Tell everyone else that this player's selected item has changed.
}
if ( ItemStack selectedStack = player.getInventory().getSelectedItemStack();
now - lastResupplyAt > server.getConfig().actions.resupplyCooldown * 1000 && if (selectedStack instanceof BlockItemStack b) {
player.getTeam() != null && tickBlockAction(now, server, world, b);
player.getPosition().distance(player.getTeam().getSpawnPoint()) < server.getConfig().actions.resupplyRadius } else if (selectedStack instanceof GunItemStack g) {
) { tickGunAction(now, server, g);
server.getPlayerManager().resupply(player); }
lastResupplyAt = now;
if (
now - lastResupplyAt > server.getConfig().actions.resupplyCooldown * 1000 &&
player.getTeam() != null &&
player.getPosition().distance(player.getTeam().getSpawnPoint()) < server.getConfig().actions.resupplyRadius
) {
server.getPlayerManager().resupply(player);
lastResupplyAt = now;
}
} }
if (player.getMode() == PlayerMode.NORMAL && server.getConfig().actions.healthRegenPerSecond != 0 && player.getHealth() < 1) { if (player.getMode() == PlayerMode.NORMAL && server.getConfig().actions.healthRegenPerSecond != 0 && player.getHealth() < 1) {

View File

@ -2,10 +2,7 @@ package nl.andrewl.aos2_server.model;
import nl.andrewl.aos2_server.logic.PlayerActionManager; import nl.andrewl.aos2_server.logic.PlayerActionManager;
import nl.andrewl.aos_core.model.Player; import nl.andrewl.aos_core.model.Player;
import nl.andrewl.aos_core.model.item.BlockItemStack;
import nl.andrewl.aos_core.model.item.GunItemStack;
import nl.andrewl.aos_core.model.item.Inventory; import nl.andrewl.aos_core.model.item.Inventory;
import nl.andrewl.aos_core.model.item.ItemTypes;
import nl.andrewl.aos_core.net.client.PlayerUpdateMessage; import nl.andrewl.aos_core.net.client.PlayerUpdateMessage;
import java.util.ArrayList; import java.util.ArrayList;
@ -32,10 +29,6 @@ public class ServerPlayer extends Player {
this.inventory = new Inventory(new ArrayList<>(), 0); this.inventory = new Inventory(new ArrayList<>(), 0);
this.health = 1f; this.health = 1f;
this.actionManager = new PlayerActionManager(this); this.actionManager = new PlayerActionManager(this);
inventory.getItemStacks().add(new GunItemStack(ItemTypes.RIFLE));
inventory.getItemStacks().add(new GunItemStack(ItemTypes.AK_47));
inventory.getItemStacks().add(new GunItemStack(ItemTypes.WINCHESTER));
inventory.getItemStacks().add(new BlockItemStack(ItemTypes.BLOCK, 50, (byte) 1));
} }
public PlayerActionManager getActionManager() { public PlayerActionManager getActionManager() {
@ -84,7 +77,7 @@ public class ServerPlayer extends Player {
velocity.x, velocity.y, velocity.z, velocity.x, velocity.y, velocity.z,
orientation.x, orientation.y, orientation.x, orientation.y,
actionManager.getInput().crouching(), actionManager.getInput().crouching(),
inventory.getSelectedItemStack().getType().getId(), inventory.getSelectedItemStack() == null ? -1 : inventory.getSelectedItemStack().getType().getId(),
mode mode
); );
} }