Added smoother client control!
This commit is contained in:
parent
7cbfa258f4
commit
fbd893915b
|
@ -20,15 +20,17 @@ import org.joml.Vector3f;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.awt.image.RenderedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
public class Client implements Runnable {
|
public class Client implements Runnable {
|
||||||
private static final Logger log = LoggerFactory.getLogger(Client.class);
|
private static final Logger log = LoggerFactory.getLogger(Client.class);
|
||||||
public static final double FPS = 60;
|
|
||||||
|
|
||||||
private final ClientConfig config;
|
private final ClientConfig config;
|
||||||
private final CommunicationHandler communicationHandler;
|
private final CommunicationHandler communicationHandler;
|
||||||
|
@ -43,6 +45,7 @@ public class Client implements Runnable {
|
||||||
private final Map<Integer, Projectile> projectiles;
|
private final Map<Integer, Projectile> projectiles;
|
||||||
private final Map<Integer, Team> teams;
|
private final Map<Integer, Team> teams;
|
||||||
private final Chat chat;
|
private final Chat chat;
|
||||||
|
private final Queue<Runnable> mainThreadActions;
|
||||||
|
|
||||||
public Client(ClientConfig config) {
|
public Client(ClientConfig config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
@ -52,6 +55,7 @@ public class Client implements Runnable {
|
||||||
this.communicationHandler = new CommunicationHandler(this);
|
this.communicationHandler = new CommunicationHandler(this);
|
||||||
this.inputHandler = new InputHandler(this, communicationHandler);
|
this.inputHandler = new InputHandler(this, communicationHandler);
|
||||||
this.chat = new Chat();
|
this.chat = new Chat();
|
||||||
|
this.mainThreadActions = new ConcurrentLinkedQueue<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientConfig getConfig() {
|
public ClientConfig getConfig() {
|
||||||
|
@ -80,8 +84,9 @@ public class Client implements Runnable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gameRenderer = new GameRenderer(config.display, this);
|
gameRenderer = new GameRenderer(this);
|
||||||
gameRenderer.setupWindow(
|
gameRenderer.setupWindow(
|
||||||
|
inputHandler,
|
||||||
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),
|
||||||
|
@ -94,12 +99,17 @@ public class Client implements Runnable {
|
||||||
while (!gameRenderer.windowShouldClose() && !communicationHandler.isDone()) {
|
while (!gameRenderer.windowShouldClose() && !communicationHandler.isDone()) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
float dt = (now - lastFrameAt) / 1000f;
|
float dt = (now - lastFrameAt) / 1000f;
|
||||||
|
|
||||||
world.processQueuedChunkUpdates();
|
world.processQueuedChunkUpdates();
|
||||||
|
while (!mainThreadActions.isEmpty()) {
|
||||||
|
mainThreadActions.remove().run();
|
||||||
|
}
|
||||||
soundManager.updateListener(myPlayer.getPosition(), myPlayer.getVelocity());
|
soundManager.updateListener(myPlayer.getPosition(), myPlayer.getVelocity());
|
||||||
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, now);
|
||||||
|
|
||||||
gameRenderer.draw();
|
gameRenderer.draw();
|
||||||
lastFrameAt = now;
|
lastFrameAt = now;
|
||||||
}
|
}
|
||||||
|
@ -118,25 +128,27 @@ public class Client implements Runnable {
|
||||||
communicationHandler.sendMessage(new ChunkHashMessage(u.cx(), u.cy(), u.cz(), -1));
|
communicationHandler.sendMessage(new ChunkHashMessage(u.cx(), u.cy(), u.cz(), -1));
|
||||||
}
|
}
|
||||||
} else if (msg instanceof PlayerUpdateMessage playerUpdate) {
|
} else if (msg instanceof PlayerUpdateMessage playerUpdate) {
|
||||||
if (playerUpdate.clientId() == myPlayer.getId() && playerUpdate.timestamp() > lastPlayerUpdate) {
|
runLater(() -> {
|
||||||
myPlayer.getPosition().set(playerUpdate.px(), playerUpdate.py(), playerUpdate.pz());
|
if (playerUpdate.clientId() == myPlayer.getId() && playerUpdate.timestamp() > lastPlayerUpdate) {
|
||||||
myPlayer.getVelocity().set(playerUpdate.vx(), playerUpdate.vy(), playerUpdate.vz());
|
myPlayer.getPosition().set(playerUpdate.px(), playerUpdate.py(), playerUpdate.pz());
|
||||||
myPlayer.setCrouching(playerUpdate.crouching());
|
myPlayer.getVelocity().set(playerUpdate.vx(), playerUpdate.vy(), playerUpdate.vz());
|
||||||
if (gameRenderer != null) {
|
myPlayer.setCrouching(playerUpdate.crouching());
|
||||||
gameRenderer.getCamera().setToPlayer(myPlayer);
|
if (gameRenderer != null) {
|
||||||
|
gameRenderer.getCamera().setToPlayer(myPlayer);
|
||||||
|
}
|
||||||
|
if (soundManager != null) {
|
||||||
|
soundManager.updateListener(myPlayer.getPosition(), myPlayer.getVelocity());
|
||||||
|
}
|
||||||
|
lastPlayerUpdate = playerUpdate.timestamp();
|
||||||
|
} else {
|
||||||
|
OtherPlayer p = players.get(playerUpdate.clientId());
|
||||||
|
if (p != null) {
|
||||||
|
playerUpdate.apply(p);
|
||||||
|
p.setHeldItemId(playerUpdate.selectedItemId());
|
||||||
|
p.updateModelTransform();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (soundManager != null) {
|
});
|
||||||
soundManager.updateListener(myPlayer.getPosition(), myPlayer.getVelocity());
|
|
||||||
}
|
|
||||||
lastPlayerUpdate = playerUpdate.timestamp();
|
|
||||||
} else {
|
|
||||||
OtherPlayer p = players.get(playerUpdate.clientId());
|
|
||||||
if (p != null) {
|
|
||||||
playerUpdate.apply(p);
|
|
||||||
p.setHeldItemId(playerUpdate.selectedItemId());
|
|
||||||
p.updateModelTransform();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (msg instanceof ClientInventoryMessage inventoryMessage) {
|
} else if (msg instanceof ClientInventoryMessage inventoryMessage) {
|
||||||
myPlayer.setInventory(inventoryMessage.inv());
|
myPlayer.setInventory(inventoryMessage.inv());
|
||||||
} else if (msg instanceof InventorySelectedStackMessage selectedStackMessage) {
|
} else if (msg instanceof InventorySelectedStackMessage selectedStackMessage) {
|
||||||
|
@ -149,19 +161,23 @@ public class Client implements Runnable {
|
||||||
player.setSelectedBlockValue(blockColorMessage.block());
|
player.setSelectedBlockValue(blockColorMessage.block());
|
||||||
}
|
}
|
||||||
} else if (msg instanceof PlayerJoinMessage joinMessage) {
|
} else if (msg instanceof PlayerJoinMessage joinMessage) {
|
||||||
Player p = joinMessage.toPlayer();
|
runLater(() -> {
|
||||||
OtherPlayer op = new OtherPlayer(p.getId(), p.getUsername());
|
Player p = joinMessage.toPlayer();
|
||||||
if (joinMessage.teamId() != -1) {
|
OtherPlayer op = new OtherPlayer(p.getId(), p.getUsername());
|
||||||
op.setTeam(teams.get(joinMessage.teamId()));
|
if (joinMessage.teamId() != -1) {
|
||||||
}
|
op.setTeam(teams.get(joinMessage.teamId()));
|
||||||
op.getPosition().set(p.getPosition());
|
}
|
||||||
op.getVelocity().set(p.getVelocity());
|
op.getPosition().set(p.getPosition());
|
||||||
op.getOrientation().set(p.getOrientation());
|
op.getVelocity().set(p.getVelocity());
|
||||||
op.setHeldItemId(joinMessage.selectedItemId());
|
op.getOrientation().set(p.getOrientation());
|
||||||
op.setSelectedBlockValue(joinMessage.selectedBlockValue());
|
op.setHeldItemId(joinMessage.selectedItemId());
|
||||||
players.put(op.getId(), op);
|
op.setSelectedBlockValue(joinMessage.selectedBlockValue());
|
||||||
|
players.put(op.getId(), op);
|
||||||
|
});
|
||||||
} else if (msg instanceof PlayerLeaveMessage leaveMessage) {
|
} else if (msg instanceof PlayerLeaveMessage leaveMessage) {
|
||||||
players.remove(leaveMessage.id());
|
runLater(() -> {
|
||||||
|
players.remove(leaveMessage.id());
|
||||||
|
});
|
||||||
} else if (msg instanceof SoundMessage soundMessage) {
|
} else if (msg instanceof SoundMessage soundMessage) {
|
||||||
if (soundManager != null) {
|
if (soundManager != null) {
|
||||||
soundManager.play(
|
soundManager.play(
|
||||||
|
@ -172,17 +188,19 @@ public class Client implements Runnable {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (msg instanceof ProjectileMessage pm) {
|
} else if (msg instanceof ProjectileMessage pm) {
|
||||||
Projectile p = projectiles.get(pm.id());
|
runLater(() -> {
|
||||||
if (p == null && !pm.destroyed()) {
|
Projectile p = projectiles.get(pm.id());
|
||||||
p = new Projectile(pm.id(), new Vector3f(pm.px(), pm.py(), pm.pz()), new Vector3f(pm.vx(), pm.vy(), pm.vz()), pm.type());
|
if (p == null && !pm.destroyed()) {
|
||||||
projectiles.put(p.getId(), p);
|
p = new Projectile(pm.id(), new Vector3f(pm.px(), pm.py(), pm.pz()), new Vector3f(pm.vx(), pm.vy(), pm.vz()), pm.type());
|
||||||
} else if (p != null) {
|
projectiles.put(p.getId(), p);
|
||||||
p.getPosition().set(pm.px(), pm.py(), pm.pz()); // Don't update position, it's too short of a timeframe to matter.
|
} else if (p != null) {
|
||||||
p.getVelocity().set(pm.vx(), pm.vy(), pm.vz());
|
p.getPosition().set(pm.px(), pm.py(), pm.pz()); // Don't update position, it's too short of a timeframe to matter.
|
||||||
if (pm.destroyed()) {
|
p.getVelocity().set(pm.vx(), pm.vy(), pm.vz());
|
||||||
projectiles.remove(p.getId());
|
if (pm.destroyed()) {
|
||||||
|
projectiles.remove(p.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
} else if (msg instanceof ClientHealthMessage healthMessage) {
|
} else if (msg instanceof ClientHealthMessage healthMessage) {
|
||||||
myPlayer.setHealth(healthMessage.health());
|
myPlayer.setHealth(healthMessage.health());
|
||||||
} else if (msg instanceof ChatMessage chatMessage) {
|
} else if (msg instanceof ChatMessage chatMessage) {
|
||||||
|
@ -201,6 +219,10 @@ public class Client implements Runnable {
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InputHandler getInputHandler() {
|
||||||
|
return inputHandler;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<Integer, Team> getTeams() {
|
public Map<Integer, Team> getTeams() {
|
||||||
return teams;
|
return teams;
|
||||||
}
|
}
|
||||||
|
@ -217,6 +239,10 @@ public class Client implements Runnable {
|
||||||
return chat;
|
return chat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SoundManager getSoundManager() {
|
||||||
|
return soundManager;
|
||||||
|
}
|
||||||
|
|
||||||
public void interpolatePlayers(long now, float dt) {
|
public void interpolatePlayers(long now, float dt) {
|
||||||
Vector3f movement = new Vector3f();
|
Vector3f movement = new Vector3f();
|
||||||
for (var player : players.values()) {
|
for (var player : players.values()) {
|
||||||
|
@ -236,6 +262,10 @@ public class Client implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void runLater(Runnable runnable) {
|
||||||
|
mainThreadActions.add(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
List<Path> configPaths = Config.getCommonConfigPaths();
|
List<Path> configPaths = Config.getCommonConfigPaths();
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
|
|
|
@ -17,6 +17,8 @@ public class InputHandler {
|
||||||
private final Client client;
|
private final Client client;
|
||||||
private final CommunicationHandler comm;
|
private final CommunicationHandler comm;
|
||||||
|
|
||||||
|
private long windowId;
|
||||||
|
|
||||||
private ClientInputState lastInputState = null;
|
private ClientInputState lastInputState = null;
|
||||||
|
|
||||||
private boolean forward;
|
private boolean forward;
|
||||||
|
@ -29,6 +31,9 @@ public class InputHandler {
|
||||||
private boolean hitting;
|
private boolean hitting;
|
||||||
private boolean interacting;
|
private boolean interacting;
|
||||||
private boolean reloading;
|
private boolean reloading;
|
||||||
|
private int selectedInventoryIndex;
|
||||||
|
|
||||||
|
private boolean debugEnabled;
|
||||||
|
|
||||||
|
|
||||||
public InputHandler(Client client, CommunicationHandler comm) {
|
public InputHandler(Client client, CommunicationHandler comm) {
|
||||||
|
@ -36,27 +41,16 @@ public class InputHandler {
|
||||||
this.comm = comm;
|
this.comm = comm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateInputState(long window) {
|
public void setWindowId(long windowId) {
|
||||||
// TODO: Allow customized keybindings.
|
this.windowId = windowId;
|
||||||
int selectedInventoryIndex;
|
}
|
||||||
selectedInventoryIndex = client.getMyPlayer().getInventory().getSelectedIndex();
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS) selectedInventoryIndex = 0;
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_2) == GLFW_PRESS) selectedInventoryIndex = 1;
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_3) == GLFW_PRESS) selectedInventoryIndex = 2;
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_4) == GLFW_PRESS) selectedInventoryIndex = 3;
|
|
||||||
|
|
||||||
|
public void updateInputState() {
|
||||||
ClientInputState currentInputState = new ClientInputState(
|
ClientInputState currentInputState = new ClientInputState(
|
||||||
comm.getClientId(),
|
comm.getClientId(),
|
||||||
glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS,
|
forward, backward, left, right,
|
||||||
glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS,
|
jumping, crouching, sprinting,
|
||||||
glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS,
|
hitting, interacting, reloading,
|
||||||
glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS,
|
|
||||||
glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS,
|
|
||||||
glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS,
|
|
||||||
glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS,
|
|
||||||
glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS,
|
|
||||||
glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_2) == GLFW_PRESS,
|
|
||||||
glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS,
|
|
||||||
selectedInventoryIndex
|
selectedInventoryIndex
|
||||||
);
|
);
|
||||||
if (!currentInputState.equals(lastInputState)) {
|
if (!currentInputState.equals(lastInputState)) {
|
||||||
|
@ -67,7 +61,7 @@ public class InputHandler {
|
||||||
ClientPlayer player = client.getMyPlayer();
|
ClientPlayer player = client.getMyPlayer();
|
||||||
|
|
||||||
// Check for "pick block" functionality.
|
// Check for "pick block" functionality.
|
||||||
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_3) == GLFW_PRESS && player.getInventory().getSelectedItemStack() instanceof BlockItemStack stack) {
|
if (glfwGetMouseButton(windowId, GLFW_MOUSE_BUTTON_3) == GLFW_PRESS && player.getInventory().getSelectedItemStack() instanceof BlockItemStack stack) {
|
||||||
Hit hit = client.getWorld().getLookingAtPos(player.getEyePosition(), player.getViewVector(), 50);
|
Hit hit = client.getWorld().getLookingAtPos(player.getEyePosition(), player.getViewVector(), 50);
|
||||||
if (hit != null) {
|
if (hit != null) {
|
||||||
byte selectedBlock = client.getWorld().getBlockAt(hit.pos().x, hit.pos().y, hit.pos().z);
|
byte selectedBlock = client.getWorld().getBlockAt(hit.pos().x, hit.pos().y, hit.pos().z);
|
||||||
|
@ -78,4 +72,111 @@ public class InputHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isForward() {
|
||||||
|
return forward;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForward(boolean forward) {
|
||||||
|
this.forward = forward;
|
||||||
|
updateInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBackward() {
|
||||||
|
return backward;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackward(boolean backward) {
|
||||||
|
this.backward = backward;
|
||||||
|
updateInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLeft() {
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLeft(boolean left) {
|
||||||
|
this.left = left;
|
||||||
|
updateInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRight() {
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRight(boolean right) {
|
||||||
|
this.right = right;
|
||||||
|
updateInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isJumping() {
|
||||||
|
return jumping;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJumping(boolean jumping) {
|
||||||
|
this.jumping = jumping;
|
||||||
|
updateInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCrouching() {
|
||||||
|
return crouching;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCrouching(boolean crouching) {
|
||||||
|
this.crouching = crouching;
|
||||||
|
updateInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSprinting() {
|
||||||
|
return sprinting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSprinting(boolean sprinting) {
|
||||||
|
this.sprinting = sprinting;
|
||||||
|
updateInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHitting() {
|
||||||
|
return hitting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHitting(boolean hitting) {
|
||||||
|
this.hitting = hitting;
|
||||||
|
updateInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInteracting() {
|
||||||
|
return interacting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInteracting(boolean interacting) {
|
||||||
|
this.interacting = interacting;
|
||||||
|
updateInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReloading() {
|
||||||
|
return reloading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReloading(boolean reloading) {
|
||||||
|
this.reloading = reloading;
|
||||||
|
updateInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSelectedInventoryIndex() {
|
||||||
|
return selectedInventoryIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelectedInventoryIndex(int selectedInventoryIndex) {
|
||||||
|
this.selectedInventoryIndex = selectedInventoryIndex;
|
||||||
|
updateInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDebugEnabled() {
|
||||||
|
return debugEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleDebugEnabled() {
|
||||||
|
this.debugEnabled = !debugEnabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,37 @@ public class PlayerInputKeyCallback implements GLFWKeyCallbackI {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke(long window, int key, int scancode, int action, int mods) {
|
public void invoke(long window, int key, int scancode, int action, int mods) {
|
||||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
|
if (action == GLFW_PRESS) {
|
||||||
glfwSetWindowShouldClose(window, true);
|
switch (key) {
|
||||||
|
case GLFW_KEY_W -> inputHandler.setForward(true);
|
||||||
|
case GLFW_KEY_A -> inputHandler.setLeft(true);
|
||||||
|
case GLFW_KEY_S -> inputHandler.setBackward(true);
|
||||||
|
case GLFW_KEY_D -> inputHandler.setRight(true);
|
||||||
|
case GLFW_KEY_SPACE -> inputHandler.setJumping(true);
|
||||||
|
case GLFW_KEY_LEFT_CONTROL -> inputHandler.setCrouching(true);
|
||||||
|
case GLFW_KEY_LEFT_SHIFT -> inputHandler.setSprinting(true);
|
||||||
|
case GLFW_KEY_R -> inputHandler.setReloading(true);
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
} else if (action == GLFW_RELEASE) {
|
||||||
|
switch (key) {
|
||||||
|
case GLFW_KEY_W -> inputHandler.setForward(false);
|
||||||
|
case GLFW_KEY_A -> inputHandler.setLeft(false);
|
||||||
|
case GLFW_KEY_S -> inputHandler.setBackward(false);
|
||||||
|
case GLFW_KEY_D -> inputHandler.setRight(false);
|
||||||
|
case GLFW_KEY_SPACE -> inputHandler.setJumping(false);
|
||||||
|
case GLFW_KEY_LEFT_CONTROL -> inputHandler.setCrouching(false);
|
||||||
|
case GLFW_KEY_LEFT_SHIFT -> inputHandler.setSprinting(false);
|
||||||
|
case GLFW_KEY_R -> inputHandler.setReloading(false);
|
||||||
|
|
||||||
|
case GLFW_KEY_ESCAPE -> glfwSetWindowShouldClose(window, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
inputHandler.updateInputState(window);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package nl.andrewl.aos2_client.control;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFWMouseButtonCallbackI;
|
import org.lwjgl.glfw.GLFWMouseButtonCallbackI;
|
||||||
|
|
||||||
|
import static org.lwjgl.glfw.GLFW.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback that's called when the player clicks with their mouse.
|
* Callback that's called when the player clicks with their mouse.
|
||||||
*/
|
*/
|
||||||
|
@ -14,6 +16,16 @@ public class PlayerInputMouseClickCallback implements GLFWMouseButtonCallbackI {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke(long window, int button, int action, int mods) {
|
public void invoke(long window, int button, int action, int mods) {
|
||||||
inputHandler.updateInputState(window);
|
if (action == GLFW_PRESS) {
|
||||||
|
switch (button) {
|
||||||
|
case GLFW_MOUSE_BUTTON_1 -> inputHandler.setHitting(true);
|
||||||
|
case GLFW_MOUSE_BUTTON_2 -> inputHandler.setInteracting(true);
|
||||||
|
}
|
||||||
|
} else if (action == GLFW_RELEASE) {
|
||||||
|
switch (button) {
|
||||||
|
case GLFW_MOUSE_BUTTON_1 -> inputHandler.setHitting(false);
|
||||||
|
case GLFW_MOUSE_BUTTON_2 -> inputHandler.setInteracting(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package nl.andrewl.aos2_client.render;
|
||||||
import nl.andrewl.aos2_client.Camera;
|
import nl.andrewl.aos2_client.Camera;
|
||||||
import nl.andrewl.aos2_client.Client;
|
import nl.andrewl.aos2_client.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.model.ClientPlayer;
|
import nl.andrewl.aos2_client.model.ClientPlayer;
|
||||||
import nl.andrewl.aos2_client.render.chunk.ChunkRenderer;
|
import nl.andrewl.aos2_client.render.chunk.ChunkRenderer;
|
||||||
import nl.andrewl.aos2_client.render.gui.GuiRenderer;
|
import nl.andrewl.aos2_client.render.gui.GuiRenderer;
|
||||||
|
@ -56,8 +57,8 @@ public class GameRenderer {
|
||||||
|
|
||||||
private final Matrix4f perspectiveTransform;
|
private final Matrix4f perspectiveTransform;
|
||||||
|
|
||||||
public GameRenderer(ClientConfig.DisplayConfig config, Client client) {
|
public GameRenderer(Client client) {
|
||||||
this.config = config;
|
this.config = client.getConfig().display;
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.camera = new Camera();
|
this.camera = new Camera();
|
||||||
camera.setToPlayer(client.getMyPlayer());
|
camera.setToPlayer(client.getMyPlayer());
|
||||||
|
@ -65,6 +66,7 @@ public class GameRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setupWindow(
|
public void setupWindow(
|
||||||
|
InputHandler inputHandler,
|
||||||
GLFWCursorPosCallbackI viewCursorCallback,
|
GLFWCursorPosCallbackI viewCursorCallback,
|
||||||
GLFWKeyCallbackI inputKeyCallback,
|
GLFWKeyCallbackI inputKeyCallback,
|
||||||
GLFWMouseButtonCallbackI mouseButtonCallback,
|
GLFWMouseButtonCallbackI mouseButtonCallback,
|
||||||
|
@ -90,6 +92,7 @@ public class GameRenderer {
|
||||||
windowHandle = glfwCreateWindow(screenWidth, screenHeight, "Ace of Shades 2", 0, 0);
|
windowHandle = glfwCreateWindow(screenWidth, screenHeight, "Ace of Shades 2", 0, 0);
|
||||||
}
|
}
|
||||||
if (windowHandle == 0) throw new RuntimeException("Failed to create GLFW window.");
|
if (windowHandle == 0) throw new RuntimeException("Failed to create GLFW window.");
|
||||||
|
inputHandler.setWindowId(windowHandle);
|
||||||
log.debug("Initialized GLFW window.");
|
log.debug("Initialized GLFW window.");
|
||||||
|
|
||||||
// Setup callbacks.
|
// Setup callbacks.
|
||||||
|
@ -110,7 +113,7 @@ public class GameRenderer {
|
||||||
|
|
||||||
GL.createCapabilities();
|
GL.createCapabilities();
|
||||||
// GLUtil.setupDebugMessageCallback(System.out);
|
// GLUtil.setupDebugMessageCallback(System.out);
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glCullFace(GL_BACK);
|
glCullFace(GL_BACK);
|
||||||
|
@ -259,7 +262,7 @@ public class GameRenderer {
|
||||||
flagModel.bind();
|
flagModel.bind();
|
||||||
for (Team team : client.getTeams().values()) {
|
for (Team team : client.getTeams().values()) {
|
||||||
modelTransform.identity()
|
modelTransform.identity()
|
||||||
.translate(team.getSpawnPoint());
|
.translate(team.getSpawnPoint().x() - 0.25f, team.getSpawnPoint().y(), team.getSpawnPoint().z() - 0.25f);
|
||||||
modelTransform.normal(normalTransform);
|
modelTransform.normal(normalTransform);
|
||||||
modelRenderer.setAspectColor(team.getColor());
|
modelRenderer.setAspectColor(team.getColor());
|
||||||
modelRenderer.render(flagModel, modelTransform, normalTransform);
|
modelRenderer.render(flagModel, modelTransform, normalTransform);
|
||||||
|
@ -271,7 +274,7 @@ public class GameRenderer {
|
||||||
// GUI rendering
|
// GUI rendering
|
||||||
guiRenderer.start();
|
guiRenderer.start();
|
||||||
guiRenderer.drawNameplates(myPlayer, camera.getViewTransformData(), perspectiveTransform.get(new float[16]));
|
guiRenderer.drawNameplates(myPlayer, camera.getViewTransformData(), perspectiveTransform.get(new float[16]));
|
||||||
guiRenderer.drawNvg(screenWidth, screenHeight, myPlayer, client.getChat());
|
guiRenderer.drawNvg(screenWidth, screenHeight, client);
|
||||||
guiRenderer.end();
|
guiRenderer.end();
|
||||||
|
|
||||||
glfwSwapBuffers(windowHandle);
|
glfwSwapBuffers(windowHandle);
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package nl.andrewl.aos2_client.render.gui;
|
package nl.andrewl.aos2_client.render.gui;
|
||||||
|
|
||||||
import nl.andrewl.aos2_client.Camera;
|
import nl.andrewl.aos2_client.Camera;
|
||||||
|
import nl.andrewl.aos2_client.Client;
|
||||||
import nl.andrewl.aos2_client.model.Chat;
|
import nl.andrewl.aos2_client.model.Chat;
|
||||||
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.ShaderProgram;
|
import nl.andrewl.aos2_client.render.ShaderProgram;
|
||||||
|
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.item.BlockItem;
|
import nl.andrewl.aos_core.model.item.BlockItem;
|
||||||
|
@ -216,14 +218,17 @@ public class GuiRenderer {
|
||||||
shaderProgram.use();
|
shaderProgram.use();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawNvg(float width, float height, ClientPlayer player, Chat chat) {
|
public void drawNvg(float width, float height, Client client) {
|
||||||
nvgBeginFrame(vgId, width, height, width / height);
|
nvgBeginFrame(vgId, width, height, width / height);
|
||||||
nvgSave(vgId);
|
nvgSave(vgId);
|
||||||
|
|
||||||
drawCrosshair(width, height);
|
drawCrosshair(width, height);
|
||||||
drawChat(width, height, chat);
|
drawChat(width, height, client.getChat());
|
||||||
drawHealthBar(width, height, player);
|
drawHealthBar(width, height, client.getMyPlayer());
|
||||||
drawHeldItemStackInfo(width, height, player);
|
drawHeldItemStackInfo(width, height, client.getMyPlayer());
|
||||||
|
if (client.getInputHandler().isDebugEnabled()) {
|
||||||
|
drawDebugInfo(width, height, client);
|
||||||
|
}
|
||||||
|
|
||||||
nvgRestore(vgId);
|
nvgRestore(vgId);
|
||||||
nvgEndFrame(vgId);
|
nvgEndFrame(vgId);
|
||||||
|
@ -346,4 +351,30 @@ public class GuiRenderer {
|
||||||
y -= 16;
|
y -= 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void drawDebugInfo(float w, float h, Client client) {
|
||||||
|
float y = h / 4 + 10;
|
||||||
|
nvgFontSize(vgId, 12f);
|
||||||
|
nvgFontFaceId(vgId, jetbrainsMonoFont);
|
||||||
|
nvgTextAlign(vgId, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
|
||||||
|
nvgFillColor(vgId, GuiUtils.rgba(1, 1, 1, 1, colorA));
|
||||||
|
var pos = client.getMyPlayer().getPosition();
|
||||||
|
nvgText(vgId, 5, y, String.format("Pos: x=%.3f, y=%.3f, z=%.3f", pos.x, pos.y, pos.z));
|
||||||
|
y += 12;
|
||||||
|
var vel = client.getMyPlayer().getVelocity();
|
||||||
|
nvgText(vgId, 5, y, String.format("Vel: x=%.3f, y=%.3f, z=%.3f, speed=%.3f", vel.x, vel.y, vel.z, vel.length()));
|
||||||
|
y += 12;
|
||||||
|
var view = client.getMyPlayer().getOrientation();
|
||||||
|
nvgText(vgId, 5, y, String.format("View: horizontal=%.3f, vertical=%.3f", Math.toDegrees(view.x), Math.toDegrees(view.y)));
|
||||||
|
y += 12;
|
||||||
|
var soundSources = client.getSoundManager().getSources();
|
||||||
|
int activeCount = (int) soundSources.stream().filter(SoundSource::isPlaying).count();
|
||||||
|
nvgText(vgId, 5, y, String.format("Sounds: %d / %d playing", activeCount, soundSources.size()));
|
||||||
|
y += 12;
|
||||||
|
nvgText(vgId, 5, y, String.format("Projectiles: %d", client.getProjectiles().size()));
|
||||||
|
y += 12;
|
||||||
|
nvgText(vgId, 5, y, String.format("Players: %d", client.getPlayers().size()));
|
||||||
|
y += 12;
|
||||||
|
nvgText(vgId, 5, y, String.format("Chunks: %d", client.getWorld().getChunkMap().size()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,7 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
@ -133,6 +130,10 @@ public class SoundManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<SoundSource> getSources() {
|
||||||
|
return Collections.unmodifiableCollection(availableSources);
|
||||||
|
}
|
||||||
|
|
||||||
private SoundSource getNextAvailableSoundSource() {
|
private SoundSource getNextAvailableSoundSource() {
|
||||||
for (var source : availableSources) {
|
for (var source : availableSources) {
|
||||||
if (!source.isPlaying()) return source;
|
if (!source.isPlaying()) return source;
|
||||||
|
|
Loading…
Reference in New Issue