diff --git a/client/pom.xml b/client/pom.xml index 6912333..6fc7531 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -146,6 +146,11 @@ aos2-core ${parent.version} + + de.javagl + obj + 0.3.0 + org.lwjgl diff --git a/client/src/main/java/nl/andrewl/aos2_client/Client.java b/client/src/main/java/nl/andrewl/aos2_client/Client.java index 57b06cf..3815a84 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/Client.java +++ b/client/src/main/java/nl/andrewl/aos2_client/Client.java @@ -5,16 +5,11 @@ 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.render.GameRenderer; -import nl.andrewl.aos_core.model.Chunk; import nl.andrewl.aos_core.model.ColorPalette; -import nl.andrewl.aos_core.model.World; -import nl.andrewl.aos_core.net.ChunkDataMessage; -import nl.andrewl.aos_core.net.ChunkHashMessage; -import nl.andrewl.aos_core.net.WorldInfoMessage; +import nl.andrewl.aos_core.net.*; import nl.andrewl.aos_core.net.udp.ChunkUpdateMessage; import nl.andrewl.aos_core.net.udp.PlayerUpdateMessage; import nl.andrewl.record_net.Message; -import org.joml.Vector3i; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,14 +55,18 @@ public class Client implements Runnable { gameRenderer.setupWindow( new PlayerViewCursorCallback(gameRenderer.getCamera(), communicationHandler), new PlayerInputKeyCallback(inputHandler), - new PlayerInputMouseClickCallback(inputHandler) + new PlayerInputMouseClickCallback(inputHandler), + false, + false ); long lastFrameAt = System.currentTimeMillis(); while (!gameRenderer.windowShouldClose()) { long now = System.currentTimeMillis(); float dt = (now - lastFrameAt) / 1000f; + world.processQueuedChunkUpdates(); gameRenderer.getCamera().interpolatePosition(dt); + world.interpolatePlayers(dt); gameRenderer.draw(); lastFrameAt = now; } @@ -75,31 +74,17 @@ public class Client implements Runnable { communicationHandler.shutdown(); } - public int getClientId() { - return clientId; - } - - public World getWorld() { - return world; - } - public void onMessageReceived(Message msg) { if (msg instanceof WorldInfoMessage worldInfo) { world.setPalette(ColorPalette.fromArray(worldInfo.palette())); } if (msg instanceof ChunkDataMessage chunkDataMessage) { - Chunk chunk = chunkDataMessage.toChunk(); - world.addChunk(chunk); - gameRenderer.getChunkRenderer().queueChunkMesh(chunk); + world.addChunk(chunkDataMessage); } if (msg instanceof ChunkUpdateMessage u) { - Vector3i chunkPos = new Vector3i(u.cx(), u.cy(), u.cz()); - Chunk chunk = world.getChunkAt(chunkPos); - System.out.println(u); - if (chunk != null) { - chunk.setBlockAt(u.lx(), u.ly(), u.lz(), u.newBlock()); - gameRenderer.getChunkRenderer().queueChunkMesh(chunk); - } else { + world.updateChunk(u); + // If we received an update for a chunk we don't have, request it! + if (world.getChunkAt(u.getChunkPos()) == null) { communicationHandler.sendMessage(new ChunkHashMessage(u.cx(), u.cy(), u.cz(), -1)); } } @@ -108,9 +93,16 @@ public class Client implements Runnable { float eyeHeight = playerUpdate.crouching() ? 1.3f : 1.7f; gameRenderer.getCamera().setPosition(playerUpdate.px(), playerUpdate.py() + eyeHeight, playerUpdate.pz()); gameRenderer.getCamera().setVelocity(playerUpdate.vx(), playerUpdate.vy(), playerUpdate.vz()); - // TODO: Unload far away chunks and request close chunks we don't have. + } else { + world.playerUpdated(playerUpdate); } } + if (msg instanceof PlayerJoinMessage joinMessage) { + world.playerJoined(joinMessage); + } + if (msg instanceof PlayerLeaveMessage leaveMessage) { + world.playerLeft(leaveMessage); + } } diff --git a/client/src/main/java/nl/andrewl/aos2_client/ClientWorld.java b/client/src/main/java/nl/andrewl/aos2_client/ClientWorld.java index b434ada..b163577 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/ClientWorld.java +++ b/client/src/main/java/nl/andrewl/aos2_client/ClientWorld.java @@ -1,7 +1,138 @@ package nl.andrewl.aos2_client; +import nl.andrewl.aos2_client.render.chunk.ChunkMesh; +import nl.andrewl.aos2_client.render.chunk.ChunkMeshGenerator; +import nl.andrewl.aos_core.model.Chunk; +import nl.andrewl.aos_core.model.Player; import nl.andrewl.aos_core.model.World; +import nl.andrewl.aos_core.net.ChunkDataMessage; +import nl.andrewl.aos_core.net.PlayerJoinMessage; +import nl.andrewl.aos_core.net.PlayerLeaveMessage; +import nl.andrewl.aos_core.net.udp.ChunkUpdateMessage; +import nl.andrewl.aos_core.net.udp.PlayerUpdateMessage; +import org.joml.Vector3f; +import org.joml.Vector3i; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * A client-side extension of the world model, with information that is only + * important for the client to know about, like other players and chunk render + * queues. + */ public class ClientWorld extends World { + private final Queue chunkUpdateQueue = new ConcurrentLinkedQueue<>(); + private final Queue chunkRemovalQueue = new ConcurrentLinkedQueue<>(); + private final ChunkMeshGenerator chunkMeshGenerator = new ChunkMeshGenerator(); + private final Map chunkMeshes = new ConcurrentHashMap<>(); + private final Map players = new HashMap<>(); + + public void playerJoined(PlayerJoinMessage joinMessage) { + Player p = joinMessage.toPlayer(); + players.put(p.getId(), p); + } + + public void playerLeft(PlayerLeaveMessage leaveMessage) { + players.remove(leaveMessage.id()); + } + + public void playerUpdated(PlayerUpdateMessage playerUpdate) { + Player p = players.get(playerUpdate.clientId()); + if (p != null) { + playerUpdate.apply(p); + } + } + + public Collection getPlayers() { + return players.values(); + } + + public void interpolatePlayers(float dt) { + Vector3f movement = new Vector3f(); + for (var player : getPlayers()) { + movement.set(player.getVelocity()).mul(dt); + player.getPosition().add(movement); + } + } + + @Override + public void addChunk(Chunk chunk) { + super.addChunk(chunk); + chunkUpdateQueue.add(chunk); + } + + public void addChunk(ChunkDataMessage msg) { + addChunk(msg.toChunk()); + } + + @Override + public void removeChunk(Vector3i chunkPos) { + Chunk chunk = getChunkAt(chunkPos); + if (chunk != null) { + chunkRemovalQueue.add(chunk); + chunkUpdateQueue.remove(chunk); + } + super.removeChunk(chunkPos); + } + + public void updateChunk(ChunkUpdateMessage update) { + Chunk chunk = getChunkAt(update.getChunkPos()); + if (chunk != null) { + chunk.setBlockAt(update.lx(), update.ly(), update.lz(), update.newBlock()); + List chunksToReRender = new ArrayList<>(7); + chunksToReRender.add(chunk); + // Check if neighboring chunks need to be re-rendered too. + if (update.lx() == 0) { + Chunk c = getChunkAt(update.cx() - 1, update.cy(), update.cz()); + if (c != null) chunksToReRender.add(c); + } + if (update.ly() == 0) { + Chunk c = getChunkAt(update.cx(), update.cy() - 1, update.cz()); + if (c != null) chunksToReRender.add(c); + } + if (update.lz() == 0) { + Chunk c = getChunkAt(update.cx(), update.cy(), update.cz() - 1); + if (c != null) chunksToReRender.add(c); + } + if (update.lx() == Chunk.SIZE - 1) { + Chunk c = getChunkAt(update.cx() + 1, update.cy(), update.cz()); + if (c != null) chunksToReRender.add(c); + } + if (update.ly() == Chunk.SIZE - 1) { + Chunk c = getChunkAt(update.cx(), update.cy() + 1, update.cz()); + if (c != null) chunksToReRender.add(c); + } + if (update.lz() == Chunk.SIZE - 1) { + Chunk c = getChunkAt(update.cx(), update.cy(), update.cz() + 1); + if (c != null) chunksToReRender.add(c); + } + chunkUpdateQueue.addAll(chunksToReRender); + } + } + + /** + * Call this to process any queued chunk updates, and update chunk meshes. + * Only call this method on the main OpenGL context thread! + */ + public void processQueuedChunkUpdates() { + while (!chunkRemovalQueue.isEmpty()) { + Chunk chunk = chunkRemovalQueue.remove(); + ChunkMesh mesh = chunkMeshes.remove(chunk); + if (mesh != null) mesh.free(); + } + while (!chunkUpdateQueue.isEmpty()) { + Chunk chunk = chunkUpdateQueue.remove(); + ChunkMesh mesh = new ChunkMesh(chunk, this, chunkMeshGenerator); + ChunkMesh existingMesh = chunkMeshes.get(chunk); + if (existingMesh != null) existingMesh.free(); + chunkMeshes.put(chunk, mesh); + } + } + + public Collection getChunkMeshesToDraw() { + return chunkMeshes.values(); + } } diff --git a/client/src/main/java/nl/andrewl/aos2_client/control/PlayerInputMouseClickCallback.java b/client/src/main/java/nl/andrewl/aos2_client/control/PlayerInputMouseClickCallback.java index b4c63fe..7f8a4f6 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/control/PlayerInputMouseClickCallback.java +++ b/client/src/main/java/nl/andrewl/aos2_client/control/PlayerInputMouseClickCallback.java @@ -14,7 +14,6 @@ public class PlayerInputMouseClickCallback implements GLFWMouseButtonCallbackI { @Override public void invoke(long window, int button, int action, int mods) { - System.out.println("Click: " + button); inputHandler.updateInputState(window); } } diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/GameRenderer.java b/client/src/main/java/nl/andrewl/aos2_client/render/GameRenderer.java index 58d5924..a66f5b1 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/render/GameRenderer.java +++ b/client/src/main/java/nl/andrewl/aos2_client/render/GameRenderer.java @@ -1,10 +1,11 @@ package nl.andrewl.aos2_client.render; import nl.andrewl.aos2_client.Camera; +import nl.andrewl.aos2_client.ClientWorld; import nl.andrewl.aos2_client.render.chunk.ChunkRenderer; import nl.andrewl.aos2_client.render.gui.GUIRenderer; import nl.andrewl.aos2_client.render.gui.GUITexture; -import nl.andrewl.aos_core.model.World; +import nl.andrewl.aos2_client.render.model.Model; import org.joml.Matrix4f; import org.lwjgl.glfw.*; import org.lwjgl.opengl.GL; @@ -27,30 +28,33 @@ public class GameRenderer { private static final float Z_NEAR = 0.01f; private static final float Z_FAR = 500f; - private final ChunkRenderer chunkRenderer; - private final GUIRenderer guiRenderer; + private ChunkRenderer chunkRenderer; + private GUIRenderer guiRenderer; + private ModelRenderer modelRenderer; private final Camera camera; - private final World world; + private final ClientWorld world; + private Model playerModel; // Standard player model used to render all players. private long windowHandle; - private GLFWVidMode primaryMonitorSettings; - private boolean fullscreen; private int screenWidth = 800; private int screenHeight = 600; private float fov = 90f; private final Matrix4f perspectiveTransform; - public GameRenderer(World world) { + public GameRenderer(ClientWorld world) { this.world = world; - this.chunkRenderer = new ChunkRenderer(); - this.guiRenderer = new GUIRenderer(); this.camera = new Camera(); this.perspectiveTransform = new Matrix4f(); - } - public void setupWindow(GLFWCursorPosCallbackI viewCursorCallback, GLFWKeyCallbackI inputKeyCallback, GLFWMouseButtonCallbackI mouseButtonCallback) { + public void setupWindow( + GLFWCursorPosCallbackI viewCursorCallback, + GLFWKeyCallbackI inputKeyCallback, + GLFWMouseButtonCallbackI mouseButtonCallback, + boolean fullscreen, + boolean grabCursor + ) { GLFWErrorCallback.createPrint(System.err).set(); if (!glfwInit()) throw new IllegalStateException("Could not initialize GLFW."); glfwDefaultWindowHints(); @@ -58,21 +62,28 @@ public class GameRenderer { glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); long monitorId = glfwGetPrimaryMonitor(); - primaryMonitorSettings = glfwGetVideoMode(monitorId); + GLFWVidMode primaryMonitorSettings = glfwGetVideoMode(monitorId); if (primaryMonitorSettings == null) throw new IllegalStateException("Could not get information about the primary monitory."); log.debug("Primary monitor settings: Width: {}, Height: {}", primaryMonitorSettings.width(), primaryMonitorSettings.height()); - screenWidth = primaryMonitorSettings.width(); - screenHeight = primaryMonitorSettings.height(); - windowHandle = glfwCreateWindow(screenWidth, screenHeight, "Ace of Shades 2", monitorId, 0); + if (fullscreen) { + screenWidth = primaryMonitorSettings.width(); + screenHeight = primaryMonitorSettings.height(); + windowHandle = glfwCreateWindow(screenWidth, screenHeight, "Ace of Shades 2", monitorId, 0); + } else { + screenWidth = 1000; + screenHeight = 800; + windowHandle = glfwCreateWindow(screenWidth, screenHeight, "Ace of Shades 2", 0, 0); + } if (windowHandle == 0) throw new RuntimeException("Failed to create GLFW window."); - fullscreen = true; log.debug("Initialized GLFW window."); // Setup callbacks. glfwSetKeyCallback(windowHandle, inputKeyCallback); glfwSetCursorPosCallback(windowHandle, viewCursorCallback); glfwSetMouseButtonCallback(windowHandle, mouseButtonCallback); - glfwSetInputMode(windowHandle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + if (grabCursor) { + glfwSetInputMode(windowHandle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + } glfwSetInputMode(windowHandle, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); glfwSetCursorPos(windowHandle, 0, 0); log.debug("Set up window callbacks."); @@ -80,7 +91,6 @@ public class GameRenderer { glfwMakeContextCurrent(windowHandle); glfwSwapInterval(1); glfwShowWindow(windowHandle); - log.debug("Made window visible."); GL.createCapabilities(); // GLUtil.setupDebugMessageCallback(System.out); @@ -90,9 +100,9 @@ public class GameRenderer { glCullFace(GL_BACK); log.debug("Initialized OpenGL context."); - chunkRenderer.setupShaderProgram(); + this.chunkRenderer = new ChunkRenderer(); log.debug("Initialized chunk renderer."); - guiRenderer.setup(); + this.guiRenderer = new GUIRenderer(); // TODO: More organized way to load textures for GUI. try { var crosshairTexture = new GUITexture("gui/crosshair.png"); @@ -103,34 +113,13 @@ public class GameRenderer { throw new RuntimeException(e); } log.debug("Initialized GUI renderer."); - updatePerspective(); - } - - public void setFullscreen(boolean fullscreen) { - if (windowHandle == 0) throw new IllegalStateException("Window not setup."); - long monitor = glfwGetPrimaryMonitor(); - if (fullscreen) { - log.debug("Changing to fullscreen: {} x {}", primaryMonitorSettings.width(), primaryMonitorSettings.height()); - glfwSetWindowMonitor(windowHandle, monitor, 0, 0, primaryMonitorSettings.width(), primaryMonitorSettings.height(), primaryMonitorSettings.refreshRate()); - screenWidth = primaryMonitorSettings.width(); - screenHeight = primaryMonitorSettings.height(); - updatePerspective(); - } else { - log.debug("Changing to windowed mode."); - screenWidth = 800; - screenHeight = 600; - int left = primaryMonitorSettings.width() / 2; - int top = primaryMonitorSettings.height() / 2; - glfwSetWindowMonitor(windowHandle, 0, left, top, screenWidth, screenHeight, primaryMonitorSettings.refreshRate()); - updatePerspective(); + this.modelRenderer = new ModelRenderer(); + try { + playerModel = new Model("model/player_simple.obj", "model/simple_player.png"); + } catch (IOException e) { + throw new RuntimeException(e); } - this.fullscreen = fullscreen; - } - - public void setSize(int width, int height) { - glfwSetWindowSize(windowHandle, width, height); - this.screenWidth = width; - this.screenHeight = height; + log.debug("Initialized model renderer."); updatePerspective(); } @@ -144,12 +133,18 @@ public class GameRenderer { } /** - * Updates the rendering perspective used to render the game. Note: only - * call this after calling {@link ChunkRenderer#setupShaderProgram()}. + * Updates the rendering perspective used to render the game. */ private void updatePerspective() { perspectiveTransform.setPerspective(fov, getAspectRatio(), Z_NEAR, Z_FAR); - chunkRenderer.setPerspective(perspectiveTransform); + float[] data = new float[16]; + perspectiveTransform.get(data); + if (chunkRenderer != null) chunkRenderer.setPerspective(data); + if (modelRenderer != null) modelRenderer.setPerspective(data); + } + + public Matrix4f getPerspectiveTransform() { + return perspectiveTransform; } public boolean windowShouldClose() { @@ -160,14 +155,20 @@ public class GameRenderer { return camera; } - public ChunkRenderer getChunkRenderer() { - return chunkRenderer; - } - public void draw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + chunkRenderer.draw(camera, world.getChunkMeshesToDraw()); + + // Draw players. + modelRenderer.setView(camera.getViewTransformData()); + playerModel.bind(); + Matrix4f playerModelTransform = new Matrix4f(); + for (var player : world.getPlayers()) { + playerModelTransform.identity().translate(player.getPosition()); + modelRenderer.render(playerModel, playerModelTransform); + } + playerModel.unbind(); - chunkRenderer.draw(camera, world); guiRenderer.draw(); glfwSwapBuffers(windowHandle); @@ -175,8 +176,10 @@ public class GameRenderer { } public void freeWindow() { - guiRenderer.free(); - chunkRenderer.free(); + if (playerModel != null) playerModel.free(); + if (modelRenderer != null) modelRenderer.free(); + if (guiRenderer != null) guiRenderer.free(); + if (chunkRenderer != null) chunkRenderer.free(); GL.destroy(); Callbacks.glfwFreeCallbacks(windowHandle); glfwSetErrorCallback(null); diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/Mesh.java b/client/src/main/java/nl/andrewl/aos2_client/render/Mesh.java deleted file mode 100644 index e815948..0000000 --- a/client/src/main/java/nl/andrewl/aos2_client/render/Mesh.java +++ /dev/null @@ -1,70 +0,0 @@ -package nl.andrewl.aos2_client.render; - -import org.joml.Matrix4f; - -import static org.lwjgl.opengl.GL46.*; - -public class Mesh { - private final int vboId; - private final int vaoId; - private final int eboId; - private int indexCount; - private final Matrix4f transform = new Matrix4f(); - private final float[] transformData = new float[16]; - - public Mesh(MeshData initialData) { - this.vboId = glGenBuffers(); - this.eboId = glGenBuffers(); - this.vaoId = glGenVertexArrays(); - load(initialData); - initVertexArrayAttributes(); - } - - public void load(MeshData data) { - indexCount = data.indexBuffer().limit(); - glBindBuffer(GL_ARRAY_BUFFER, vboId); - glBufferData(GL_ARRAY_BUFFER, data.vertexBuffer(), GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.indexBuffer(), GL_STATIC_DRAW); - } - - public Matrix4f getTransform() { - return transform; - } - - public void updateTransform() { - transform.set(transformData); - } - - public float[] getTransformData() { - return transformData; - } - - /** - * Initializes this mesh's vertex array attribute settings. - */ - private void initVertexArrayAttributes() { - glBindVertexArray(vaoId); - // Vertex position floats. - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, false, 9 * Float.BYTES, 0); - // Vertex color floats. - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, false, 9 * Float.BYTES, 3 * Float.BYTES); - // Vertex normal floats. - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 3, GL_FLOAT, false, 9 * Float.BYTES, 6 * Float.BYTES); - } - - public void draw() { - glBindVertexArray(vaoId); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId); - glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0); - } - - public void free() { - glDeleteBuffers(vboId); - glDeleteBuffers(eboId); - glDeleteVertexArrays(vaoId); - } -} diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/MeshData.java b/client/src/main/java/nl/andrewl/aos2_client/render/MeshData.java deleted file mode 100644 index fde20be..0000000 --- a/client/src/main/java/nl/andrewl/aos2_client/render/MeshData.java +++ /dev/null @@ -1,6 +0,0 @@ -package nl.andrewl.aos2_client.render; - -import java.nio.FloatBuffer; -import java.nio.IntBuffer; - -public record MeshData(FloatBuffer vertexBuffer, IntBuffer indexBuffer) {} diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/ModelRenderer.java b/client/src/main/java/nl/andrewl/aos2_client/render/ModelRenderer.java new file mode 100644 index 0000000..3c26344 --- /dev/null +++ b/client/src/main/java/nl/andrewl/aos2_client/render/ModelRenderer.java @@ -0,0 +1,53 @@ +package nl.andrewl.aos2_client.render; + +import nl.andrewl.aos2_client.Camera; +import nl.andrewl.aos2_client.render.model.Model; +import org.joml.Matrix4f; + +import static org.lwjgl.opengl.GL46.*; + +/** + * A renderer that handles rendering of textured models. + */ +public class ModelRenderer { + private final ShaderProgram shaderProgram; + private final int projectionUniform; + private final int viewUniform; + private final int modelUniform; + private final int textureSamplerUniform; + + public ModelRenderer() { + shaderProgram = new ShaderProgram.Builder() + .withShader("shader/model/vertex.glsl", GL_VERTEX_SHADER) + .withShader("shader/model/fragment.glsl", GL_FRAGMENT_SHADER) + .build(); + projectionUniform = shaderProgram.getUniform("projectionTransform"); + viewUniform = shaderProgram.getUniform("viewTransform"); + modelUniform = shaderProgram.getUniform("modelTransform"); + textureSamplerUniform = shaderProgram.getUniform("textureSampler"); + } + + public void setPerspective(float[] data) { + shaderProgram.use(); + glUniformMatrix4fv(projectionUniform, false, data); + shaderProgram.stopUsing(); + } + + public void setView(float[] data) { + shaderProgram.use(); + glUniformMatrix4fv(viewUniform, false, data); + shaderProgram.stopUsing(); + } + + public void render(Model model, Matrix4f modelTransform) { + shaderProgram.use(); + glUniformMatrix4fv(modelUniform, false, modelTransform.get(new float[16])); + glUniform1i(textureSamplerUniform, 0); + model.draw(); + shaderProgram.stopUsing(); + } + + public void free() { + shaderProgram.free(); + } +} diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/PlayerMeshGenerator.java b/client/src/main/java/nl/andrewl/aos2_client/render/PlayerMeshGenerator.java deleted file mode 100644 index db831ca..0000000 --- a/client/src/main/java/nl/andrewl/aos2_client/render/PlayerMeshGenerator.java +++ /dev/null @@ -1,26 +0,0 @@ -package nl.andrewl.aos2_client.render; - -import org.joml.Vector3f; -import org.joml.Vector3i; -import org.lwjgl.BufferUtils; - -import java.nio.FloatBuffer; -import java.nio.IntBuffer; - -public class PlayerMeshGenerator { - private final FloatBuffer vertexBuffer; - private final IntBuffer indexBuffer; - - private final Vector3i pos = new Vector3i(); - private final Vector3f color = new Vector3f(); - private final Vector3f norm = new Vector3f(); - - public PlayerMeshGenerator() { - vertexBuffer = BufferUtils.createFloatBuffer(1000); - indexBuffer = BufferUtils.createIntBuffer(100); - } - -// public PlayerMesh generateMesh() { -// -// } -} diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/ShaderProgram.java b/client/src/main/java/nl/andrewl/aos2_client/render/ShaderProgram.java index 7b1f30e..2557509 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/render/ShaderProgram.java +++ b/client/src/main/java/nl/andrewl/aos2_client/render/ShaderProgram.java @@ -32,6 +32,10 @@ public class ShaderProgram { glUseProgram(0); } + public int getId() { + return id; + } + public int getUniform(String name) { return glGetUniformLocation(id, name); } diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/chunk/ChunkMesh.java b/client/src/main/java/nl/andrewl/aos2_client/render/chunk/ChunkMesh.java index 4192bc9..5363b32 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/render/chunk/ChunkMesh.java +++ b/client/src/main/java/nl/andrewl/aos2_client/render/chunk/ChunkMesh.java @@ -49,17 +49,16 @@ public class ChunkMesh { * Generates and loads this chunk's mesh into the allocated OpenGL buffers. */ private void loadMesh(ChunkMeshGenerator meshGenerator) { - long start = System.nanoTime(); +// long start = System.nanoTime(); var meshData = meshGenerator.generateMesh(chunk, world); - double dur = (System.nanoTime() - start) / 1_000_000.0; +// double dur = (System.nanoTime() - start) / 1_000_000.0; this.indexCount = meshData.indexBuffer().limit(); - // Print some debug information. - log.debug( - "Generated mesh for chunk ({}, {}, {}) in {} ms. {} vertices and {} indices.", - chunk.getPosition().x, chunk.getPosition().y, chunk.getPosition().z, - dur, - meshData.vertexBuffer().limit() / 9, indexCount - ); +// log.debug( +// "Generated mesh for chunk ({}, {}, {}) in {} ms. {} vertices and {} indices.", +// chunk.getPosition().x, chunk.getPosition().y, chunk.getPosition().z, +// dur, +// meshData.vertexBuffer().limit() / 9, indexCount +// ); glBindBuffer(GL_ARRAY_BUFFER, vboId); glBufferData(GL_ARRAY_BUFFER, meshData.vertexBuffer(), GL_STATIC_DRAW); diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/chunk/ChunkRenderer.java b/client/src/main/java/nl/andrewl/aos2_client/render/chunk/ChunkRenderer.java index db3b697..0b8184e 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/render/chunk/ChunkRenderer.java +++ b/client/src/main/java/nl/andrewl/aos2_client/render/chunk/ChunkRenderer.java @@ -7,7 +7,10 @@ import nl.andrewl.aos_core.model.World; import org.joml.Matrix4f; import org.joml.Vector3i; -import java.util.*; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import static org.lwjgl.opengl.GL46.*; @@ -18,17 +21,12 @@ import static org.lwjgl.opengl.GL46.*; * be rendered each frame. */ public class ChunkRenderer { - private final ChunkMeshGenerator chunkMeshGenerator = new ChunkMeshGenerator(); - private final Queue meshGenerationQueue = new ConcurrentLinkedQueue<>(); + private final ShaderProgram shaderProgram; + private final int projectionTransformUniform; + private final int viewTransformUniform; + private final int chunkPositionUniform; - private ShaderProgram shaderProgram; - private int projectionTransformUniform; - private int viewTransformUniform; - private int chunkPositionUniform; - - private final Map chunkMeshes = new HashMap<>(); - - public void setupShaderProgram() { + public ChunkRenderer() { this.shaderProgram = new ShaderProgram.Builder() .withShader("shader/chunk/vertex.glsl", GL_VERTEX_SHADER) .withShader("shader/chunk/fragment.glsl", GL_FRAGMENT_SHADER) @@ -38,39 +36,28 @@ public class ChunkRenderer { this.viewTransformUniform = shaderProgram.getUniform("viewTransform"); this.chunkPositionUniform = shaderProgram.getUniform("chunkPosition"); int chunkSizeUniform = shaderProgram.getUniform("chunkSize"); - // Set constant uniforms that don't change during runtime. glUniform1i(chunkSizeUniform, Chunk.SIZE); + shaderProgram.stopUsing(); } - public void queueChunkMesh(Chunk chunk) { - meshGenerationQueue.add(chunk); + public void setPerspective(float[] data) { + shaderProgram.use(); + glUniformMatrix4fv(projectionTransformUniform, false, data); + shaderProgram.stopUsing(); } - public void setPerspective(Matrix4f projectionTransform) { - glUniformMatrix4fv(projectionTransformUniform, false, projectionTransform.get(new float[16])); - } - - public void draw(Camera cam, World world) { - while (!meshGenerationQueue.isEmpty()) { - Chunk chunk = meshGenerationQueue.remove(); - ChunkMesh mesh = new ChunkMesh(chunk, world, chunkMeshGenerator); - ChunkMesh existingMesh = chunkMeshes.get(chunk.getPosition()); - if (existingMesh != null) existingMesh.free(); - chunkMeshes.put(chunk.getPosition(), mesh); - } + public void draw(Camera cam, Collection chunkMeshes) { shaderProgram.use(); glUniformMatrix4fv(viewTransformUniform, false, cam.getViewTransformData()); - for (var mesh : chunkMeshes.values()) { + for (var mesh : chunkMeshes) { glUniform3iv(chunkPositionUniform, mesh.getPositionData()); mesh.draw(); } + shaderProgram.stopUsing(); } public void free() { - for (var mesh : chunkMeshes.values()) mesh.free(); - chunkMeshes.clear(); - meshGenerationQueue.clear(); shaderProgram.free(); } } diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/gui/GUIRenderer.java b/client/src/main/java/nl/andrewl/aos2_client/render/gui/GUIRenderer.java index a263a4c..ba6dc99 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/render/gui/GUIRenderer.java +++ b/client/src/main/java/nl/andrewl/aos2_client/render/gui/GUIRenderer.java @@ -14,20 +14,16 @@ import static org.lwjgl.opengl.GL46.*; * Manages rendering of 2D GUI components like cross-hairs, inventory stuff, etc. */ public class GUIRenderer { - private int vaoId; - private int vboId; - private int vertexCount; - private ShaderProgram shaderProgram; - private int transformUniformLocation; + private final int vaoId; + private final int vboId; + private final int vertexCount; + private final ShaderProgram shaderProgram; + private final int transformUniformLocation; private final List guiTextures = new ArrayList<>(); - public void addTexture(GUITexture texture) { - guiTextures.add(texture); - } - - public void setup() { + public GUIRenderer() { vaoId = glGenVertexArrays(); vboId = glGenBuffers(); FloatBuffer buffer = BufferUtils.createFloatBuffer(8); @@ -53,6 +49,10 @@ public class GUIRenderer { shaderProgram.bindAttribute(0, "position"); } + public void addTexture(GUITexture texture) { + guiTextures.add(texture); + } + public void draw() { shaderProgram.use(); glBindVertexArray(vaoId); diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/gui/GUITexture.java b/client/src/main/java/nl/andrewl/aos2_client/render/gui/GUITexture.java index 4cc345d..59d15ce 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/render/gui/GUITexture.java +++ b/client/src/main/java/nl/andrewl/aos2_client/render/gui/GUITexture.java @@ -26,7 +26,7 @@ public class GUITexture { textureId = glGenTextures(); glBindTexture(GL_TEXTURE_2D, textureId); - glPixelStorei(GL_UNPACK_ALIGNMENT, textureId); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); var buf = ImageUtils.decodePng(img); diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/model/Model.java b/client/src/main/java/nl/andrewl/aos2_client/render/model/Model.java new file mode 100644 index 0000000..205b76a --- /dev/null +++ b/client/src/main/java/nl/andrewl/aos2_client/render/model/Model.java @@ -0,0 +1,123 @@ +package nl.andrewl.aos2_client.render.model; + +import de.javagl.obj.Obj; +import de.javagl.obj.ObjData; +import de.javagl.obj.ObjReader; +import de.javagl.obj.ObjUtils; +import nl.andrewl.aos_core.ImageUtils; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.List; + +import static org.lwjgl.opengl.GL46.*; + +/** + * Represents a 3D model with a texture, which can be used to render one or + * more entities. + */ +public class Model { + private final int vaoId; + private final List vboIds; + private final int eboId; + private final int indexCount; + private final int textureId; + + public Model(String resource, String textureResource) throws IOException { + try ( + var in = Model.class.getClassLoader().getResourceAsStream(resource); + var imageIn = Model.class.getClassLoader().getResourceAsStream(textureResource) + ) { + if (in == null) throw new IOException("Could not load resource: " + resource); + if (imageIn == null) throw new IOException("Could not load texture image: " + textureResource); + Obj obj = ObjReader.read(in); + obj = ObjUtils.convertToRenderable(obj); + IntBuffer indices = ObjData.getFaceVertexIndices(obj, 3); + FloatBuffer vertices = ObjData.getVertices(obj); + FloatBuffer texCoords = ObjData.getTexCoords(obj, 2, true); + FloatBuffer normals = ObjData.getNormals(obj); + indexCount = indices.limit(); + + vboIds = new ArrayList<>(4); + + vaoId = glGenVertexArrays(); + glBindVertexArray(vaoId); + + // Position data + int vboId = glGenBuffers(); + vboIds.add(vboId); + glBindBuffer(GL_ARRAY_BUFFER, vboId); + glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0); + + // Normal data + vboId = glGenBuffers(); + vboIds.add(vboId); + glBindBuffer(GL_ARRAY_BUFFER, vboId); + glBufferData(GL_ARRAY_BUFFER, normals, GL_STATIC_DRAW); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, 0); + + // Texture data + vboId = glGenBuffers(); + vboIds.add(vboId); + glBindBuffer(GL_ARRAY_BUFFER, vboId); + glBufferData(GL_ARRAY_BUFFER, texCoords, GL_STATIC_DRAW); + glEnableVertexAttribArray(2); // Texture coordinates + glVertexAttribPointer(2, 2, GL_FLOAT, false, 0, 0); + + // Index data + eboId = glGenBuffers(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW); + + textureId = glGenTextures(); + glBindTexture(GL_TEXTURE_2D, textureId); + BufferedImage img = ImageIO.read(imageIn); + int w = img.getWidth(); + int h = img.getHeight(); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + ByteBuffer imageBuffer = ImageUtils.decodePng(img); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageBuffer); + } + } + + public void bind() { + glBindVertexArray(vaoId); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textureId); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId); + } + + public void draw() { + glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0); + } + + public void unbind() { + glBindVertexArray(0); + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + glBindTexture(GL_TEXTURE_2D, 0); + } + + public void free() { + glDeleteTextures(textureId); + glDeleteBuffers(eboId); + for (var vboId : vboIds) { + glDeleteBuffers(vboId); + } + glDeleteVertexArrays(vaoId); + } +} diff --git a/client/src/main/resources/model/player_simple.mtl b/client/src/main/resources/model/player_simple.mtl new file mode 100644 index 0000000..8f219e3 --- /dev/null +++ b/client/src/main/resources/model/player_simple.mtl @@ -0,0 +1,13 @@ +# Blender MTL File: 'player_simple.blend' +# Material Count: 1 + +newmtl Material.001 +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 +map_Kd simple_player.png diff --git a/client/src/main/resources/model/player_simple.obj b/client/src/main/resources/model/player_simple.obj new file mode 100644 index 0000000..f232464 --- /dev/null +++ b/client/src/main/resources/model/player_simple.obj @@ -0,0 +1,604 @@ +# Blender v2.82 (sub 7) OBJ File: 'player_simple.blend' +# www.blender.org +mtllib player_simple.mtl +o Cube +v 0.307055 1.384430 -0.307055 +v 0.159554 0.004036 -0.159554 +v 0.307055 1.384430 0.307055 +v 0.159554 0.004036 0.159554 +v -0.307055 1.384430 -0.307055 +v -0.159554 0.004036 -0.159554 +v -0.307055 1.384430 0.307055 +v -0.159554 0.004036 0.159554 +v 0.000000 0.004036 -0.221565 +v 0.000000 1.384430 0.426394 +v 0.000000 0.004036 0.221565 +v 0.000000 1.384430 -0.426394 +v -0.221565 0.004036 0.000000 +v 0.426394 1.384430 0.000000 +v -0.426394 1.384430 0.000000 +v 0.221565 0.004036 0.000000 +v 0.000000 0.004036 0.000000 +v 0.125637 1.521320 -0.125637 +v 0.355691 0.694233 -0.355691 +v -0.355691 0.694233 0.355691 +v 0.355691 0.694233 0.355691 +v -0.355691 0.694233 -0.355691 +v 0.000000 0.694233 -0.493931 +v 0.000000 0.694233 0.493931 +v 0.493931 0.694233 -0.000000 +v -0.493931 0.694233 -0.000000 +v 0.342552 0.349135 -0.342552 +v 0.342552 0.349135 0.342552 +v -0.342552 0.349135 -0.342552 +v 0.000000 0.349135 -0.475686 +v 0.000000 0.349135 0.475686 +v 0.475686 0.349135 -0.000000 +v -0.475686 0.349135 -0.000000 +v -0.342552 0.349135 0.342552 +v -0.342552 1.039332 0.342552 +v 0.342552 1.039332 -0.342552 +v 0.342552 1.039332 0.342552 +v -0.342552 1.039332 -0.342552 +v 0.000000 1.039332 -0.475686 +v 0.000000 1.039332 0.475686 +v 0.475686 1.039332 -0.000000 +v -0.475686 1.039332 -0.000000 +v 0.324796 0.176514 -0.324796 +v 0.324796 0.176514 0.324796 +v -0.324796 0.176514 -0.324796 +v 0.000000 0.176514 -0.451029 +v 0.000000 0.176514 0.451029 +v 0.451029 0.176514 -0.000000 +v -0.451029 0.176514 -0.000000 +v -0.324796 0.176514 0.324796 +v 0.274970 0.090275 -0.274970 +v 0.274970 0.090275 0.274970 +v -0.274970 0.090275 -0.274970 +v 0.000000 0.090275 -0.381838 +v 0.000000 0.090275 0.381838 +v 0.381838 0.090275 -0.000000 +v -0.381838 0.090275 -0.000000 +v -0.274970 0.090275 0.274970 +v 0.230376 1.470570 -0.230376 +v 0.230376 1.470570 0.230376 +v -0.230376 1.470570 -0.230376 +v -0.230376 1.470570 0.230376 +v 0.000000 1.470570 0.319913 +v 0.000000 1.470570 -0.319913 +v 0.319913 1.470570 0.000000 +v -0.319913 1.470570 0.000000 +v 0.125637 1.556870 -0.125637 +v 0.125637 1.521320 0.125637 +v -0.125637 1.521320 -0.125637 +v -0.125637 1.521320 0.125637 +v 0.000000 1.521320 0.174467 +v 0.000000 1.521320 -0.174467 +v 0.174467 1.521320 0.000000 +v -0.174467 1.521320 0.000000 +v 0.169463 1.610223 -0.169463 +v 0.125637 1.556870 0.125637 +v -0.125637 1.556870 -0.125637 +v -0.125637 1.556870 0.125637 +v 0.000000 1.556870 0.174467 +v 0.000000 1.556870 -0.174467 +v 0.174467 1.556870 0.000000 +v -0.174467 1.556870 0.000000 +v 0.210794 1.686314 -0.210794 +v 0.169463 1.610223 0.169463 +v -0.169463 1.610223 -0.169463 +v -0.169463 1.610223 0.169463 +v 0.000000 1.610223 0.235325 +v 0.000000 1.610223 -0.235325 +v 0.235325 1.610223 0.000000 +v -0.235325 1.610223 0.000000 +v 0.223284 1.833569 -0.223284 +v 0.210794 1.686314 0.210794 +v -0.210794 1.686314 -0.210794 +v -0.210794 1.686314 0.210794 +v 0.000000 1.686314 0.292720 +v 0.000000 1.686314 -0.292720 +v 0.292720 1.686314 0.000000 +v -0.292720 1.686314 0.000000 +v 0.211578 1.977176 -0.211578 +v 0.223284 1.833569 0.223284 +v -0.223284 1.833569 -0.223284 +v -0.223284 1.833569 0.223284 +v 0.000000 1.833569 0.310064 +v 0.000000 1.833569 -0.310064 +v 0.310064 1.833569 0.000000 +v -0.310064 1.833569 0.000000 +v 0.172806 2.077383 -0.172806 +v 0.211578 1.977176 0.211578 +v -0.211578 1.977176 -0.211578 +v -0.211578 1.977176 0.211578 +v 0.000000 1.977176 0.293809 +v 0.000000 1.977176 -0.293809 +v 0.293809 1.977176 0.000000 +v -0.293809 1.977176 0.000000 +v 0.067534 2.131719 -0.067534 +v 0.172806 2.077383 0.172806 +v -0.172806 2.077383 -0.172806 +v -0.172806 2.077383 0.172806 +v 0.000000 2.077383 0.239968 +v 0.000000 2.077383 -0.239968 +v 0.239968 2.077383 0.000000 +v -0.239968 2.077383 0.000000 +v 0.067534 2.131719 0.067534 +v -0.067534 2.131719 -0.067534 +v -0.067534 2.131719 0.067534 +v 0.000000 2.131719 0.093781 +v 0.000000 2.131719 -0.093781 +v 0.093781 2.131719 0.000000 +v -0.093781 2.131719 0.000000 +v 0.000000 2.131719 0.000000 +vt 0.270204 0.781152 +vt 0.118734 0.781152 +vt 0.138824 0.736777 +vt 0.252468 0.736777 +vt 0.757867 0.465320 +vt 0.690242 0.473338 +vt 0.690321 0.364703 +vt 0.757955 0.344126 +vt 0.757867 0.142172 +vt 0.690242 0.150190 +vt 0.690321 0.041556 +vt 0.757955 0.020979 +vt 0.210691 0.204882 +vt 0.247595 0.112545 +vt 0.305645 0.164231 +vt 0.305645 0.240769 +vt 0.499666 0.142172 +vt 0.432041 0.150190 +vt 0.432120 0.041555 +vt 0.499754 0.020979 +vt 0.499666 0.465320 +vt 0.432041 0.473338 +vt 0.432120 0.364703 +vt 0.499754 0.344126 +vt 0.499754 0.629641 +vt 0.432120 0.620631 +vt 0.173786 0.297218 +vt 0.252494 0.297218 +vt 0.757955 0.629641 +vt 0.690321 0.620631 +vt 0.016446 0.672518 +vt 0.016446 0.525224 +vt 0.062080 0.544760 +vt 0.062080 0.655271 +vt 0.381919 0.534391 +vt 0.381919 0.681685 +vt 0.336285 0.662149 +vt 0.336285 0.551638 +vt 0.115736 0.245532 +vt 0.115736 0.168995 +vt 0.499754 0.306493 +vt 0.432120 0.297484 +vt 0.168888 0.112545 +vt 0.757955 0.306493 +vt 0.690321 0.297484 +vt 0.893270 0.306425 +vt 0.825604 0.309807 +vt 0.825512 0.139183 +vt 0.893182 0.142104 +vt 0.635069 0.306425 +vt 0.567403 0.309807 +vt 0.567311 0.139183 +vt 0.634981 0.142104 +vt 0.893270 0.629572 +vt 0.825604 0.632954 +vt 0.825512 0.462330 +vt 0.893182 0.465251 +vt 0.635069 0.629572 +vt 0.567403 0.632954 +vt 0.567311 0.462330 +vt 0.634981 0.465251 +vt 0.567403 0.336488 +vt 0.635069 0.344058 +vt 0.567403 0.013341 +vt 0.635069 0.020910 +vt 0.825604 0.013341 +vt 0.893270 0.020910 +vt 0.825604 0.336488 +vt 0.893270 0.344058 +vt 0.927041 0.469228 +vt 0.927124 0.354316 +vt 0.927041 0.146080 +vt 0.927124 0.031169 +vt 0.668840 0.146080 +vt 0.668923 0.031169 +vt 0.668840 0.469228 +vt 0.668923 0.354316 +vt 0.668923 0.625032 +vt 0.927124 0.625032 +vt 0.668923 0.301884 +vt 0.927124 0.301884 +vt 0.282733 0.364011 +vt 0.295787 0.392847 +vt 0.135566 0.392847 +vt 0.147091 0.364011 +vt 0.138649 0.045752 +vt 0.125594 0.016917 +vt 0.285815 0.016917 +vt 0.274291 0.045752 +vt 0.374332 0.134826 +vt 0.403985 0.122132 +vt 0.403985 0.277935 +vt 0.374332 0.266728 +vt 0.047049 0.274937 +vt 0.017396 0.287632 +vt 0.017397 0.131828 +vt 0.047049 0.143035 +vt 0.145897 0.470132 +vt 0.259541 0.470132 +vt 0.232099 0.530746 +vt 0.170123 0.530746 +vt 0.124413 0.631713 +vt 0.166266 0.676163 +vt 0.228242 0.676163 +vt 0.273952 0.635464 +vt 0.124413 0.571445 +vt 0.128161 0.425756 +vt 0.279631 0.425756 +vt 0.405682 0.414476 +vt 0.405650 0.458926 +vt 0.398680 0.458930 +vt 0.398712 0.414480 +vt 0.405682 0.528622 +vt 0.405650 0.573072 +vt 0.398680 0.573076 +vt 0.398712 0.528626 +vt 0.405682 0.519194 +vt 0.398712 0.519197 +vt 0.405682 0.633340 +vt 0.398712 0.633344 +vt 0.273952 0.575196 +vt 0.907386 0.807523 +vt 0.907386 0.747255 +vt 0.933468 0.736089 +vt 0.933468 0.817380 +vt 0.799699 0.706556 +vt 0.757846 0.751006 +vt 0.731765 0.741148 +vt 0.788217 0.681193 +vt 0.757846 0.811274 +vt 0.803557 0.851973 +vt 0.793420 0.877335 +vt 0.731765 0.822439 +vt 0.865533 0.851973 +vt 0.877016 0.877335 +vt 0.413282 0.458926 +vt 0.413314 0.519194 +vt 0.406344 0.519197 +vt 0.406312 0.458930 +vt 0.421034 0.458926 +vt 0.421066 0.519194 +vt 0.414097 0.519197 +vt 0.414065 0.458930 +vt 0.421066 0.414476 +vt 0.414097 0.414480 +vt 0.413314 0.414476 +vt 0.406344 0.414480 +vt 0.783860 0.901254 +vt 0.707168 0.832969 +vt 0.887844 0.901254 +vt 0.707168 0.731852 +vt 0.871813 0.681193 +vt 0.881373 0.657274 +vt 0.958065 0.725559 +vt 0.861676 0.706556 +vt 0.059593 0.887311 +vt 0.059648 0.988429 +vt 0.030770 0.991625 +vt 0.030712 0.884517 +vt 0.997431 0.015588 +vt 0.997377 0.090166 +vt 0.968496 0.087372 +vt 0.968554 0.008375 +vt 0.997431 0.421298 +vt 0.997377 0.495876 +vt 0.968496 0.493081 +vt 0.968554 0.414084 +vt 0.997431 0.191283 +vt 0.968554 0.194480 +vt 0.777388 0.657274 +vt 0.958065 0.826676 +vt 0.940352 0.495728 +vt 0.940407 0.420873 +vt 0.940407 0.191512 +vt 0.940352 0.090019 +vt 0.968554 0.600190 +vt 0.940407 0.597221 +vt 0.030770 0.805520 +vt 0.002569 0.887164 +vt 0.002623 0.812308 +vt 0.997377 0.293021 +vt 0.997431 0.394138 +vt 0.968554 0.397335 +vt 0.968496 0.290226 +vt 0.997431 0.218443 +vt 0.968554 0.211229 +vt 0.059648 0.812733 +vt 0.997431 0.596993 +vt 0.503196 0.657315 +vt 0.607567 0.657315 +vt 0.598599 0.679753 +vt 0.513354 0.679753 +vt 0.684545 0.725854 +vt 0.684545 0.827347 +vt 0.661471 0.818627 +vt 0.661471 0.735732 +vt 0.614063 0.902203 +vt 0.603905 0.879765 +vt 0.940407 0.015163 +vt 0.002623 0.988657 +vt 0.940407 0.394367 +vt 0.940352 0.292873 +vt 0.940407 0.218018 +vt 0.576323 0.818842 +vt 0.598820 0.794949 +vt 0.598820 0.762553 +vt 0.574250 0.740676 +vt 0.455788 0.823786 +vt 0.455788 0.740891 +vt 0.518438 0.764569 +vt 0.518438 0.796965 +vt 0.518660 0.879765 +vt 0.543009 0.818842 +vt 0.509692 0.902203 +vt 0.432714 0.833664 +vt 0.432714 0.732171 +vt 0.558629 0.779759 +vt 0.540936 0.740676 +vn -0.6110 0.7552 0.2374 +vn -0.3591 0.1320 0.9239 +vn -0.9239 0.1320 -0.3591 +vn 0.0000 -1.0000 0.0000 +vn 0.9239 0.1320 0.3591 +vn 0.3591 0.1320 -0.9239 +vn -0.3591 0.1320 -0.9239 +vn 0.3591 0.1320 0.9239 +vn 0.2374 0.7552 0.6110 +vn -0.2374 0.7552 -0.6110 +vn 0.9239 0.1320 -0.3591 +vn -0.9239 0.1320 0.3591 +vn -0.2374 0.7552 0.6110 +vn -0.9309 -0.0492 0.3618 +vn 0.9309 -0.0492 -0.3618 +vn 0.3618 -0.0492 0.9309 +vn -0.3618 -0.0492 -0.9309 +vn 0.3618 -0.0492 -0.9309 +vn 0.9309 -0.0492 0.3618 +vn -0.9309 -0.0492 -0.3618 +vn -0.3618 -0.0492 0.9309 +vn -0.3591 -0.1320 0.9239 +vn -0.9239 -0.1320 -0.3591 +vn 0.9239 -0.1320 0.3591 +vn 0.3591 -0.1320 -0.9239 +vn -0.3591 -0.1320 -0.9239 +vn 0.3591 -0.1320 0.9239 +vn 0.9239 -0.1320 -0.3591 +vn -0.9239 -0.1320 0.3591 +vn -0.9309 0.0492 0.3618 +vn 0.9309 0.0492 -0.3618 +vn 0.3618 0.0492 0.9309 +vn -0.3618 0.0492 -0.9309 +vn 0.3618 0.0492 -0.9309 +vn 0.9309 0.0492 0.3618 +vn -0.9309 0.0492 -0.3618 +vn -0.3618 0.0492 0.9309 +vn -0.7464 -0.5989 0.2901 +vn 0.7464 -0.5989 -0.2901 +vn 0.2901 -0.5989 0.7464 +vn -0.2901 -0.5989 -0.7464 +vn 0.2901 -0.5989 -0.7464 +vn 0.7464 -0.5989 0.2901 +vn -0.7464 -0.5989 -0.2901 +vn -0.2901 -0.5989 0.7464 +vn -0.1811 -0.8660 0.4660 +vn -0.4660 -0.8660 -0.1811 +vn 0.4660 -0.8660 0.1811 +vn 0.1811 -0.8660 -0.4660 +vn -0.1811 -0.8660 -0.4660 +vn 0.1811 -0.8660 0.4660 +vn 0.4660 -0.8660 -0.1811 +vn -0.4660 -0.8660 0.1811 +vn 0.3268 0.9365 -0.1270 +vn -0.1270 0.9365 0.3268 +vn -0.3268 0.9365 -0.1270 +vn 0.1270 0.9365 0.3268 +vn -0.6110 0.7552 -0.2374 +vn 0.6110 0.7552 0.2374 +vn 0.6110 0.7552 -0.2374 +vn 0.2374 0.7552 -0.6110 +vn -0.3623 0.0000 0.9321 +vn -0.9321 0.0000 -0.3623 +vn 0.3623 0.0000 0.9321 +vn -0.9321 0.0000 0.3623 +vn -0.1270 0.9365 -0.3268 +vn 0.1270 0.9365 -0.3268 +vn 0.3268 0.9365 0.1270 +vn -0.3268 0.9365 0.1270 +vn -0.6386 -0.7284 0.2482 +vn 0.6386 -0.7284 0.2482 +vn 0.2482 -0.7284 -0.6386 +vn -0.2482 -0.7284 -0.6386 +vn 0.9321 0.0000 -0.3623 +vn -0.3623 0.0000 -0.9321 +vn 0.3623 0.0000 -0.9321 +vn 0.9321 0.0000 0.3623 +vn 0.2963 -0.5751 -0.7625 +vn -0.2963 -0.5751 -0.7625 +vn 0.7625 -0.5751 -0.2963 +vn -0.2963 -0.5751 0.7625 +vn 0.2482 -0.7284 0.6386 +vn -0.6386 -0.7284 -0.2482 +vn -0.2482 -0.7284 0.6386 +vn 0.6386 -0.7284 -0.2482 +vn 0.9265 -0.1091 -0.3601 +vn -0.3601 -0.1091 0.9265 +vn -0.9265 -0.1091 -0.3601 +vn 0.3601 -0.1091 0.9265 +vn 0.7625 -0.5751 0.2963 +vn -0.7625 -0.5751 0.2963 +vn 0.2963 -0.5751 0.7625 +vn -0.7625 -0.5751 -0.2963 +vn -0.9269 0.1049 -0.3603 +vn 0.3603 0.1049 0.9269 +vn -0.9269 0.1049 0.3603 +vn 0.9269 0.1049 0.3603 +vn -0.3601 -0.1091 -0.9265 +vn 0.3601 -0.1091 -0.9265 +vn 0.9265 -0.1091 0.3601 +vn -0.9265 -0.1091 0.3601 +vn 0.8334 0.4478 0.3239 +vn 0.3239 0.4478 -0.8334 +vn -0.3239 0.4478 -0.8334 +vn 0.8334 0.4478 -0.3239 +vn -0.3603 0.1049 0.9269 +vn 0.9269 0.1049 -0.3603 +vn -0.3603 0.1049 -0.9269 +vn 0.3603 0.1049 -0.9269 +vn -0.1342 0.9289 -0.3452 +vn 0.3452 0.9289 -0.1342 +vn -0.1342 0.9289 0.3452 +vn -0.3452 0.9289 -0.1342 +vn -0.8334 0.4478 0.3239 +vn 0.3239 0.4478 0.8334 +vn -0.8334 0.4478 -0.3239 +vn -0.3239 0.4478 0.8334 +vn 0.0000 1.0000 0.0000 +vn 0.1342 0.9289 -0.3452 +vn 0.3452 0.9289 0.1342 +vn -0.3452 0.9289 0.1342 +vn 0.1342 0.9289 0.3452 +usemtl Material.001 +s off +f 15/1/1 7/2/1 62/3/1 66/4/1 +f 40/5/2 10/6/2 7/7/2 35/8/2 +f 42/9/3 15/10/3 5/11/3 38/12/3 +f 17/13/4 16/14/4 4/15/4 11/16/4 +f 41/17/5 14/18/5 3/19/5 37/20/5 +f 39/21/6 12/22/6 1/23/6 36/24/6 +f 38/25/7 5/26/7 12/22/7 39/21/7 +f 13/27/4 17/13/4 11/16/4 8/28/4 +f 37/29/8 3/30/8 10/6/8 40/5/8 +f 10/31/9 3/32/9 60/33/9 63/34/9 +f 12/35/10 5/36/10 61/37/10 64/38/10 +f 6/39/4 9/40/4 17/13/4 13/27/4 +f 36/41/11 1/42/11 14/18/11 41/17/11 +f 9/40/4 2/43/4 16/14/4 17/13/4 +f 35/44/12 7/45/12 15/10/12 42/9/12 +f 7/2/13 10/31/13 63/34/13 62/3/13 +f 34/46/14 20/47/14 26/48/14 33/49/14 +f 27/50/15 19/51/15 25/52/15 32/53/15 +f 28/54/16 21/55/16 24/56/16 31/57/16 +f 29/58/17 22/59/17 23/60/17 30/61/17 +f 30/61/18 23/60/18 19/62/18 27/63/18 +f 32/53/19 25/52/19 21/64/19 28/65/19 +f 33/49/20 26/48/20 22/66/20 29/67/20 +f 31/57/21 24/56/21 20/68/21 34/69/21 +f 47/70/22 31/57/22 34/69/22 50/71/22 +f 49/72/23 33/49/23 29/67/23 45/73/23 +f 48/74/24 32/53/24 28/65/24 44/75/24 +f 46/76/25 30/61/25 27/63/25 43/77/25 +f 45/78/26 29/58/26 30/61/26 46/76/26 +f 44/79/27 28/54/27 31/57/27 47/70/27 +f 43/80/28 27/50/28 32/53/28 48/74/28 +f 50/81/29 34/46/29 33/49/29 49/72/29 +f 20/47/30 35/44/30 42/9/30 26/48/30 +f 19/51/31 36/41/31 41/17/31 25/52/31 +f 21/55/32 37/29/32 40/5/32 24/56/32 +f 22/59/33 38/25/33 39/21/33 23/60/33 +f 23/60/34 39/21/34 36/24/34 19/62/34 +f 25/52/35 41/17/35 37/20/35 21/64/35 +f 26/48/36 42/9/36 38/12/36 22/66/36 +f 24/56/37 40/5/37 35/8/37 20/68/37 +f 58/82/38 50/83/38 49/84/38 57/85/38 +f 51/86/39 43/87/39 48/88/39 56/89/39 +f 52/90/40 44/91/40 47/92/40 55/93/40 +f 53/94/41 45/95/41 46/96/41 54/97/41 +f 54/97/42 46/96/42 43/87/42 51/86/42 +f 56/89/43 48/88/43 44/91/43 52/90/43 +f 57/85/44 49/84/44 45/95/44 53/94/44 +f 55/93/45 47/92/45 50/83/45 58/82/45 +f 11/16/46 55/93/46 58/82/46 8/28/46 +f 13/27/47 57/85/47 53/94/47 6/39/47 +f 16/14/48 56/89/48 52/90/48 4/15/48 +f 9/40/49 54/97/49 51/86/49 2/43/49 +f 6/39/50 53/94/50 54/97/50 9/40/50 +f 4/15/51 52/90/51 55/93/51 11/16/51 +f 2/43/52 51/86/52 56/89/52 16/14/52 +f 8/28/53 58/82/53 57/85/53 13/27/53 +f 65/98/54 59/99/54 18/100/54 73/101/54 +f 62/3/55 63/34/55 71/102/55 70/103/55 +f 61/37/56 66/4/56 74/104/56 69/105/56 +f 63/34/57 60/33/57 68/106/57 71/102/57 +f 5/36/58 15/1/58 66/4/58 61/37/58 +f 3/32/59 14/107/59 65/98/59 60/33/59 +f 14/107/60 1/108/60 59/99/60 65/98/60 +f 1/108/61 12/35/61 64/38/61 59/99/61 +f 70/109/62 71/110/62 79/111/62 78/112/62 +f 69/113/63 74/114/63 82/115/63 77/116/63 +f 71/110/64 68/117/64 76/118/64 79/111/64 +f 74/114/65 70/119/65 78/120/65 82/115/65 +f 64/38/66 61/37/66 69/105/66 72/121/66 +f 59/99/67 64/38/67 72/121/67 18/100/67 +f 60/33/68 65/98/68 73/101/68 68/106/68 +f 66/4/69 62/3/69 70/103/69 74/104/69 +f 82/122/70 78/123/70 86/124/70 90/125/70 +f 76/126/71 81/127/71 89/128/71 84/129/71 +f 67/130/72 80/131/72 88/132/72 75/133/72 +f 80/131/73 77/134/73 85/135/73 88/132/73 +f 73/136/74 18/137/74 67/138/74 81/139/74 +f 72/140/75 69/141/75 77/142/75 80/143/75 +f 18/144/76 72/140/76 80/143/76 67/145/76 +f 68/146/77 73/136/77 81/139/77 76/147/77 +f 75/133/78 88/132/78 96/148/78 83/149/78 +f 88/132/79 85/135/79 93/150/79 96/148/79 +f 89/128/80 75/133/80 83/149/80 97/151/80 +f 86/124/81 87/152/81 95/153/81 94/154/81 +f 79/155/82 76/126/82 84/129/82 87/152/82 +f 77/134/83 82/122/83 90/125/83 85/135/83 +f 78/123/84 79/155/84 87/152/84 86/124/84 +f 81/127/85 67/130/85 75/133/85 89/128/85 +f 97/156/86 83/157/86 91/158/86 105/159/86 +f 94/160/87 95/161/87 103/162/87 102/163/87 +f 93/164/88 98/165/88 106/166/88 101/167/88 +f 95/161/89 92/168/89 100/169/89 103/162/89 +f 84/129/90 89/128/90 97/151/90 92/170/90 +f 90/125/91 86/124/91 94/154/91 98/171/91 +f 87/152/92 84/129/92 92/170/92 95/153/92 +f 85/135/93 90/125/93 98/171/93 93/150/93 +f 101/167/94 106/166/94 114/172/94 109/173/94 +f 103/162/95 100/169/95 108/174/95 111/175/95 +f 106/166/96 102/176/96 110/177/96 114/172/96 +f 100/178/97 105/159/97 113/179/97 108/180/97 +f 96/181/98 93/182/98 101/183/98 104/184/98 +f 83/185/99 96/181/99 104/184/99 91/186/99 +f 92/187/100 97/156/100 105/159/100 100/178/100 +f 98/165/101 94/188/101 102/176/101 106/166/101 +f 108/189/102 113/190/102 121/191/102 116/192/102 +f 99/193/103 112/194/103 120/195/103 107/196/103 +f 112/194/104 109/197/104 117/198/104 120/195/104 +f 113/190/105 99/193/105 107/196/105 121/191/105 +f 102/163/106 103/162/106 111/175/106 110/199/106 +f 105/159/107 91/158/107 99/200/107 113/179/107 +f 104/184/108 101/183/108 109/201/108 112/202/108 +f 91/186/109 104/184/109 112/202/109 99/203/109 +f 120/195/110 117/198/110 124/204/110 127/205/110 +f 121/191/111 107/196/111 115/206/111 128/207/111 +f 118/208/112 119/209/112 126/210/112 125/211/112 +f 117/198/113 122/212/113 129/213/113 124/204/113 +f 114/214/114 110/215/114 118/208/114 122/212/114 +f 111/216/115 108/189/115 116/192/115 119/209/115 +f 109/197/116 114/214/116 122/212/116 117/198/116 +f 110/215/117 111/216/117 119/209/117 118/208/117 +f 130/217/118 129/213/118 125/211/118 126/210/118 +f 128/207/118 130/217/118 126/210/118 123/218/118 +f 115/206/118 127/205/118 130/217/118 128/207/118 +f 127/205/118 124/204/118 129/213/118 130/217/118 +f 107/196/119 120/195/119 127/205/119 115/206/119 +f 116/192/120 121/191/120 128/207/120 123/218/120 +f 122/212/121 118/208/121 125/211/121 129/213/121 +f 119/209/122 116/192/122 123/218/122 126/210/122 diff --git a/client/src/main/resources/model/simple_player.png b/client/src/main/resources/model/simple_player.png new file mode 100644 index 0000000..e7b7d62 Binary files /dev/null and b/client/src/main/resources/model/simple_player.png differ diff --git a/client/src/main/resources/shader/model/fragment.glsl b/client/src/main/resources/shader/model/fragment.glsl new file mode 100644 index 0000000..5235c00 --- /dev/null +++ b/client/src/main/resources/shader/model/fragment.glsl @@ -0,0 +1,20 @@ +#version 460 core + +in vec2 textureCoords; +in vec3 vertexNormal; + +out vec4 fragmentColor; + +uniform sampler2D textureSampler; + +void main() { + vec4 baseColor = texture(textureSampler, textureCoords); + vec3 lightDirection = normalize(vec3(0.5, -1.0, -0.5));// TODO: Add this via a uniform. + vec3 lightColor = vec3(1.0, 1.0, 0.9); // TODO: Add this via a uniform. + + vec3 ambientComponent = vec3(0.1, 0.1, 0.1); + vec3 diffuseComponent = max(dot(vertexNormal * -1, lightDirection), 0.0) * lightColor; + // TODO: Add shading based on light. + // fragmentColor = vec4((ambientComponent + diffuseComponent), 1.0) * baseColor; + fragmentColor = baseColor; +} \ No newline at end of file diff --git a/client/src/main/resources/shader/model/vertex.glsl b/client/src/main/resources/shader/model/vertex.glsl new file mode 100644 index 0000000..9dad643 --- /dev/null +++ b/client/src/main/resources/shader/model/vertex.glsl @@ -0,0 +1,18 @@ +#version 460 core + +layout (location = 0) in vec3 vertexPositionIn; +layout (location = 1) in vec3 vertexNormalIn; +layout (location = 2) in vec2 textureCoordsIn; + +uniform mat4 projectionTransform; +uniform mat4 viewTransform; +uniform mat4 modelTransform; + +out vec2 textureCoords; +out vec3 vertexNormal; + +void main() { + gl_Position = projectionTransform * viewTransform * modelTransform * vec4(vertexPositionIn, 1.0); + vertexNormal = vec3(modelTransform * vec4(vertexNormalIn, 1.0)); + textureCoords = textureCoordsIn; +} \ No newline at end of file diff --git a/core/src/main/java/nl/andrewl/aos_core/ImageUtils.java b/core/src/main/java/nl/andrewl/aos_core/ImageUtils.java index 31f6d34..35f70a2 100644 --- a/core/src/main/java/nl/andrewl/aos_core/ImageUtils.java +++ b/core/src/main/java/nl/andrewl/aos_core/ImageUtils.java @@ -16,7 +16,7 @@ public class ImageUtils { // ARGB format to -> RGBA for( int h = 0; h < height; h++ ) for( int w = 0; w < width; w++ ) { - int argb = image.getRGB( w, h ); + int argb = image.getRGB(w, h); buf.put( (byte) ( 0xFF & ( argb >> 16 ) ) ); buf.put( (byte) ( 0xFF & ( argb >> 8 ) ) ); buf.put( (byte) ( 0xFF & ( argb ) ) ); @@ -25,4 +25,14 @@ public class ImageUtils { buf.flip(); return buf; } + + public static BufferedImage rotateClockwise90(BufferedImage src) { + int w = src.getWidth(); + int h = src.getHeight(); + BufferedImage dest = new BufferedImage(h, w, src.getType()); + for (int y = 0; y < h; y++) + for (int x = 0; x < w; x++) + dest.setRGB(y, w - x - 1, src.getRGB(x, y)); + return dest; + } } diff --git a/core/src/main/java/nl/andrewl/aos_core/model/Chunk.java b/core/src/main/java/nl/andrewl/aos_core/model/Chunk.java index ef16e08..df8eaf7 100644 --- a/core/src/main/java/nl/andrewl/aos_core/model/Chunk.java +++ b/core/src/main/java/nl/andrewl/aos_core/model/Chunk.java @@ -1,7 +1,6 @@ package nl.andrewl.aos_core.model; import net.openhft.hashing.LongHashFunction; -import org.joml.Vector3f; import org.joml.Vector3i; import java.util.Random; @@ -115,6 +114,11 @@ public class Chunk { return sb.toString(); } + @Override + public int hashCode() { + return position.hashCode(); + } + public long blockHash() { return LongHashFunction.xx3(0).hashBytes(blocks); } diff --git a/core/src/main/java/nl/andrewl/aos_core/net/PlayerJoinMessage.java b/core/src/main/java/nl/andrewl/aos_core/net/PlayerJoinMessage.java index 07d10d2..1e927f9 100644 --- a/core/src/main/java/nl/andrewl/aos_core/net/PlayerJoinMessage.java +++ b/core/src/main/java/nl/andrewl/aos_core/net/PlayerJoinMessage.java @@ -21,4 +21,12 @@ public record PlayerJoinMessage( player.getOrientation().x, player.getOrientation().y ); } + + public Player toPlayer() { + Player p = new Player(id, username); + p.getPosition().set(px, py, pz); + p.getVelocity().set(vx, vy, vz); + p.getOrientation().set(ox, oy); + return p; + } } diff --git a/core/src/main/java/nl/andrewl/aos_core/net/UdpReceiver.java b/core/src/main/java/nl/andrewl/aos_core/net/UdpReceiver.java index aed09fe..e73d6df 100644 --- a/core/src/main/java/nl/andrewl/aos_core/net/UdpReceiver.java +++ b/core/src/main/java/nl/andrewl/aos_core/net/UdpReceiver.java @@ -35,7 +35,6 @@ public class UdpReceiver implements Runnable { handler.handle(msg, packet); } catch (SocketException e) { if (e.getMessage().equals("Socket closed")) { - System.out.println("Socket closed!"); break; } e.printStackTrace(); diff --git a/core/src/main/java/nl/andrewl/aos_core/net/udp/ChunkUpdateMessage.java b/core/src/main/java/nl/andrewl/aos_core/net/udp/ChunkUpdateMessage.java index 2796b7c..0aa5ded 100644 --- a/core/src/main/java/nl/andrewl/aos_core/net/udp/ChunkUpdateMessage.java +++ b/core/src/main/java/nl/andrewl/aos_core/net/udp/ChunkUpdateMessage.java @@ -28,4 +28,12 @@ public record ChunkUpdateMessage( world.getBlockAt(worldPos.x, worldPos.y, worldPos.z) ); } + + public Vector3i getChunkPos() { + return new Vector3i(cx, cy, cz); + } + + public Vector3i getLocalPos() { + return new Vector3i(lx, ly, lz); + } } diff --git a/core/src/main/java/nl/andrewl/aos_core/net/udp/PlayerUpdateMessage.java b/core/src/main/java/nl/andrewl/aos_core/net/udp/PlayerUpdateMessage.java index 9584fc0..803540b 100644 --- a/core/src/main/java/nl/andrewl/aos_core/net/udp/PlayerUpdateMessage.java +++ b/core/src/main/java/nl/andrewl/aos_core/net/udp/PlayerUpdateMessage.java @@ -1,5 +1,6 @@ package nl.andrewl.aos_core.net.udp; +import nl.andrewl.aos_core.model.Player; import nl.andrewl.record_net.Message; /** @@ -12,4 +13,11 @@ public record PlayerUpdateMessage( float vx, float vy, float vz, float ox, float oy, boolean crouching -) implements Message {} +) implements Message { + + public void apply(Player p) { + p.getPosition().set(px, py, pz); + p.getVelocity().set(vx, vy, vz); + p.getOrientation().set(ox, oy); + } +} diff --git a/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java b/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java index b2caa60..5e9fce3 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java +++ b/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java @@ -91,6 +91,13 @@ public class ClientCommunicationHandler { log.debug("Sent connect accept message."); sendTcpMessage(new WorldInfoMessage(server.getWorld())); + // Send join info for all players that are already connected. + for (var player : server.getPlayerManager().getPlayers()) { + if (player.getId() != this.player.getId()) { + sendTcpMessage(new PlayerJoinMessage(player)); + } + } + // Send chunk data. for (var chunk : server.getWorld().getChunkMap().values()) { sendTcpMessage(new ChunkDataMessage(chunk)); }