From 98ad86cf775e2c7f5d4700a34a1cd1942da8fb56 Mon Sep 17 00:00:00 2001 From: squid233 <60126026+squid233@users.noreply.github.com> Date: Fri, 2 Aug 2024 00:20:57 +0800 Subject: [PATCH] Update entity --- .../main/java/freeworld/client/Freeworld.java | 11 ++- .../java/freeworld/client/render/Camera.java | 37 +------- .../freeworld/client/render/GameRenderer.java | 43 ++++++---- .../client/render/world/WorldRenderer.java | 37 ++++---- .../render/world/chunk/ChunkCompiler.java | 10 +-- .../world/entity/CubeEntityRenderer.java | 2 +- .../render/world/entity/EntityRenderer.java | 8 +- .../render/world/entity/EntityRenderers.java | 20 +++-- .../java/freeworld/registry/Registries.java | 3 +- .../java/freeworld/util/math/ChunkPos.java | 20 ++--- .../src/main/java/freeworld/world/World.java | 65 +++++++------- .../java/freeworld/world/chunk/Chunk.java | 40 ++++++++- .../freeworld/world/entity/CubeEntity.java | 6 +- .../java/freeworld/world/entity/Entity.java | 84 +++++++++++++------ .../freeworld/world/entity/EntityType.java | 37 ++++---- .../freeworld/world/entity/EntityTypes.java | 9 +- .../entity/{ => player}/PlayerEntity.java | 10 +-- .../world/entity/system/MotionSystem.java | 21 ++--- .../src/main/java/module-info.java | 1 + .../main/java/freeworld/math/Vector3d.java | 1 + 20 files changed, 250 insertions(+), 215 deletions(-) rename modules/freeworld.core/src/main/java/freeworld/world/entity/{ => player}/PlayerEntity.java (85%) diff --git a/modules/freeworld.client/src/main/java/freeworld/client/Freeworld.java b/modules/freeworld.client/src/main/java/freeworld/client/Freeworld.java index 01f4ad1..d4d5216 100644 --- a/modules/freeworld.client/src/main/java/freeworld/client/Freeworld.java +++ b/modules/freeworld.client/src/main/java/freeworld/client/Freeworld.java @@ -33,7 +33,7 @@ import freeworld.world.block.BlockType; import freeworld.world.block.BlockTypes; import freeworld.world.entity.EntityTypes; -import freeworld.world.entity.PlayerEntity; +import freeworld.world.entity.player.PlayerEntity; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import overrun.marshal.Unmarshal; @@ -264,7 +264,7 @@ private void worldInput() { if (!hitResult.missed() && glfw.getMouseButton(window, GLFW.MOUSE_BUTTON_LEFT) == GLFW.PRESS) { Vector3i position = hitResult.position(); - world.setBlockType(position.x(), position.y(), position.z(), BlockTypes.AIR); + world.setBlock(position.x(), position.y(), position.z(), BlockTypes.AIR); blockDestroyTimer = 0; } } @@ -278,9 +278,9 @@ private void worldInput() { Vector3i axis = face.axis(); Vector3i position = hitResult.position(); Vector3i add = position.add(axis); - if (world.getBlockType(position.x(), position.y(), position.z()).replaceable() || - world.getBlockType(add.x(), add.y(), add.z()).replaceable()) { - world.setBlockType(add.x(), add.y(), add.z(), type); + if (world.getBlock(position).replaceable() || + world.getBlock(add).replaceable()) { + world.setBlock(add.x(), add.y(), add.z(), type); } } blockPlaceTimer = 0; @@ -296,7 +296,6 @@ private void worldInput() { private void tick() { if (world != null) { - camera.preUpdate(); if (screen == null) { worldInput(); } diff --git a/modules/freeworld.client/src/main/java/freeworld/client/render/Camera.java b/modules/freeworld.client/src/main/java/freeworld/client/render/Camera.java index e559b88..32df5bc 100644 --- a/modules/freeworld.client/src/main/java/freeworld/client/render/Camera.java +++ b/modules/freeworld.client/src/main/java/freeworld/client/render/Camera.java @@ -20,46 +20,17 @@ * @since 0.1.0 */ public final class Camera { - private Vector3d prevPosition = Vector3d.ZERO; private Vector3d position = Vector3d.ZERO; - private Vector3d lerpPosition = Vector3d.ZERO; private Vector2d rotation = Vector2d.ZERO; - private Vector3d eyePosition = Vector3d.ZERO; - public void moveToEntity(Entity entity) { - eyePosition = entity.eyePosition(); - position = entity.position().add(0.0, eyePosition.y(), 0.0); + public void moveToEntity(Entity entity, double partialTick) { + position = entity.getCameraPos(partialTick); rotation = entity.rotation(); } - public void preUpdate() { - prevPosition = position; - } - - public void updateLerp(double partialTick) { - lerpPosition = prevPosition.lerp(position, partialTick); - } - public Matrix4f updateViewMatrix() { - return Matrix4f.translation((float) -eyePosition.x(), 0.0f, (float) -eyePosition.z()) - .rotateX((float) -Math.toRadians(rotation.x())) + return Matrix4f.rotationX((float) -Math.toRadians(rotation.x())) .rotateY((float) -Math.toRadians(rotation.y())) - .translate((float) -lerpPosition.x(), (float) -lerpPosition.y(), (float) -lerpPosition.z()); - } - - public Vector3d prevPosition() { - return prevPosition; - } - - public Vector3d position() { - return position; - } - - public Vector3d lerpPosition() { - return lerpPosition; - } - - public Vector2d rotation() { - return rotation; + .translate((float) -position.x(), (float) -position.y(), (float) -position.z()); } } diff --git a/modules/freeworld.client/src/main/java/freeworld/client/render/GameRenderer.java b/modules/freeworld.client/src/main/java/freeworld/client/render/GameRenderer.java index ad158a4..1e49ec5 100644 --- a/modules/freeworld.client/src/main/java/freeworld/client/render/GameRenderer.java +++ b/modules/freeworld.client/src/main/java/freeworld/client/render/GameRenderer.java @@ -27,22 +27,24 @@ import freeworld.client.render.vertex.VertexLayouts; import freeworld.client.render.world.WorldRenderer; import freeworld.client.render.world.block.BlockRenderer; +import freeworld.client.render.world.entity.EntityRenderer; import freeworld.client.render.world.entity.EntityRenderers; -import freeworld.client.world.chunk.ClientChunk; import freeworld.math.Matrix4f; import freeworld.math.Vector3i; -import freeworld.registry.Registries; import freeworld.util.Direction; import freeworld.util.Identifier; import freeworld.util.Logging; import freeworld.util.math.Lined; +import freeworld.world.World; import freeworld.world.block.BlockHitResult; import freeworld.world.entity.Entity; +import freeworld.world.entity.EntityType; import org.slf4j.Logger; import overrungl.opengl.GL10C; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * The game renderer. @@ -61,6 +63,7 @@ public final class GameRenderer implements GLResource { private BlockRenderer blockRenderer; private WorldRenderer worldRenderer; private BlockHitResult hitResult = new BlockHitResult(true, null, Vector3i.ZERO, Direction.SOUTH); + private Map, EntityRenderer> rendererMap; public GameRenderer(Freeworld client) { this.client = client; @@ -90,6 +93,8 @@ public void init(GLStateMgr gl) { guiGraphics = new GuiGraphics(gl, this); hudRenderer = new HudRenderer(this); + + rendererMap = EntityRenderers.loadRenderers(client); } private void initBlockAtlas(GLStateMgr gl) { @@ -151,8 +156,7 @@ private void renderWorld(GLStateMgr gl, double partialTick) { final Camera camera = client.camera(); final Entity player = client.player(); - camera.moveToEntity(player); - camera.updateLerp(partialTick); + camera.moveToEntity(player, partialTick); RenderSystem.setProjectionViewMatrix(Matrix4f.setPerspective( (float) Math.toRadians(70.0), (float) client.framebufferWidth() / client.framebufferHeight(), @@ -164,8 +168,7 @@ private void renderWorld(GLStateMgr gl, double partialTick) { RenderSystem.useProgram(positionColorTexProgram); RenderSystem.updateMatrices(); - final List chunks = worldRenderer.renderingChunks(player); - worldRenderer.compileChunks(chunks); + worldRenderer.compileChunks(player); hitResult = worldRenderer.selectBlock(player); @@ -175,7 +178,7 @@ private void renderWorld(GLStateMgr gl, double partialTick) { gl.setPolygonOffset(1.0f, 1.0f); gl.setLineWidth(2.0f); } - worldRenderer.renderChunks(gl, chunks); + worldRenderer.renderChunks(gl, player); if (!hitResult.missed()) { gl.disablePolygonOffsetFill(); gl.setLineWidth(1.0f); @@ -203,17 +206,23 @@ private void renderWorld(GLStateMgr gl, double partialTick) { private void renderWorldEntities(GLStateMgr gl, double partialTick) { RenderSystem.useProgram(positionColorProgram); RenderSystem.updateMatrices(); - for (Entity entity : client.world().entities()) { - entity.interpolatePosition(partialTick); - var factory = EntityRenderers.registry().getById(Registries.ENTITY_TYPE.getId(entity.entityType())); - if (factory != null) { - factory.create(client).render(gl, - partialTick, - Matrix4f.translation(entity.interpolatedPosition().toVector3f()) - .rotateY((float) Math.toRadians(entity.rotation().y())), - entity); + World.forInChunkRange(client.player(), WorldRenderer.RENDER_RADIUS, (x, y, z) -> { + for (Entity entity : client.world().getOrCreateChunk(x, y, z).entities()) { + var renderer = getEntityRenderer(entity); + if (renderer != null) { + renderer.render(gl, + partialTick, + Matrix4f.translation(entity.interpolatedPosition(partialTick).toVector3f()) + .rotateY((float) Math.toRadians(entity.rotation().y())), + entity); + } } - } + }); + } + + @SuppressWarnings("unchecked") + private EntityRenderer getEntityRenderer(T entity) { + return (EntityRenderer) rendererMap.get(entity.type()); } private void renderHud(GLStateMgr gl, double partialTick) { diff --git a/modules/freeworld.client/src/main/java/freeworld/client/render/world/WorldRenderer.java b/modules/freeworld.client/src/main/java/freeworld/client/render/world/WorldRenderer.java index 019fcc4..093ffbd 100644 --- a/modules/freeworld.client/src/main/java/freeworld/client/render/world/WorldRenderer.java +++ b/modules/freeworld.client/src/main/java/freeworld/client/render/world/WorldRenderer.java @@ -48,15 +48,18 @@ public final class WorldRenderer implements GLResource, WorldListener { private static final Logger logger = Logging.caller(); public static final int RENDER_RADIUS = 5; + private static int builtChunkCount = 0; private final GameRenderer gameRenderer; private final World world; private final Scheduler scheduler = Schedulers.newParallel("WorldRenderer-Worker"); private final Pool vertexBuilderPool = PoolBuilder .from(Mono.fromSupplier(WorldRenderer::createVertexBuilder).subscribeOn(scheduler)) .buildPool(); + @Deprecated private final Map chunks = new HashMap<>(2048); private final Disposable chunkGC; private final Queue chunkGCQueue = new LinkedBlockingQueue<>(); + @Deprecated private Vector3i playerChunkPos = Vector3i.ZERO; public WorldRenderer(GameRenderer gameRenderer, World world) { @@ -84,22 +87,15 @@ private void uninstallChunks() { } } - public List renderingChunks(Entity player) { - final List chunks = new ArrayList<>(2048); - World.forInChunkRange(player, RENDER_RADIUS, (x, y, z) -> chunks.add(getChunkOrCreate(x, y, z))); - return chunks; + public void compileChunks(Entity player) { + World.forInChunkRange(player, RENDER_RADIUS, (x, y, z) -> getChunkOrCreate(x, y, z).compile()); } - public void compileChunks(List renderingChunks) { - for (ClientChunk chunk : renderingChunks) { - chunk.compile(); - } - } - - public void renderChunks(GLStateMgr gl, List renderingChunks) { - int builtChunkCount = 0; + public void renderChunks(GLStateMgr gl, Entity player) { + builtChunkCount = 0; FrustumIntersection frustumIntersection = new FrustumIntersection(RenderSystem.projectionViewMatrix()); - for (ClientChunk chunk : renderingChunks) { + World.forInChunkRange(player, RENDER_RADIUS, (x, y, z) -> { + ClientChunk chunk = getChunkOrCreate(x, y, z); if (frustumIntersection.testAab( chunk.fromX(), chunk.fromY(), @@ -114,10 +110,10 @@ public void renderChunks(GLStateMgr gl, List renderingChunks) { } chunk.render(gl); } - } + }); Vector3d playerPos = gameRenderer.client().player().position(); - Vector3i playerChunkPos = ChunkPos.absoluteToChunk(playerPos.toVector3iFloor()); + Vector3i playerChunkPos = ChunkPos.toChunkPos(playerPos.toVector3iFloor()); if (!this.playerChunkPos.equals(playerChunkPos)) { this.playerChunkPos = playerChunkPos; uninstallChunks(); @@ -166,7 +162,7 @@ public BlockHitResult selectBlock(Entity player) { final float vz = z + 0.5f - oz; final float zSquared = vz * vz; if ((xSquared + ySquared + zSquared) <= radiusSquared) { - final BlockType blockType = world.getBlockType(x, y, z); + final BlockType blockType = world.getBlock(x, y, z); if (blockType.air()) { continue; } @@ -207,20 +203,23 @@ public void onBlockChanged(int x, int y, int z) { } } + @Deprecated private ClientChunk getChunk(int x, int y, int z) { return chunks.get(new Vector3i(x, y, z)); } + @Deprecated private ClientChunk getChunkOrCreate(int x, int y, int z) { return chunks.computeIfAbsent(new Vector3i(x, y, z), chunkPos -> new ClientChunk(world, this, chunkPos.x(), chunkPos.y(), chunkPos.z())); } + @Deprecated private ClientChunk getChunkByAbsolutePos(int x, int y, int z) { return getChunk( - ChunkPos.absoluteToChunk(x), - ChunkPos.absoluteToChunk(y), - ChunkPos.absoluteToChunk(z) + ChunkPos.toChunkPos(x), + ChunkPos.toChunkPos(y), + ChunkPos.toChunkPos(z) ); } diff --git a/modules/freeworld.client/src/main/java/freeworld/client/render/world/chunk/ChunkCompiler.java b/modules/freeworld.client/src/main/java/freeworld/client/render/world/chunk/ChunkCompiler.java index 74f9da3..1135fb5 100644 --- a/modules/freeworld.client/src/main/java/freeworld/client/render/world/chunk/ChunkCompiler.java +++ b/modules/freeworld.client/src/main/java/freeworld/client/render/world/chunk/ChunkCompiler.java @@ -51,17 +51,17 @@ public static ChunkVertexData compile( blockRenderer.renderBlockModel( vertexBuilder, model, - ChunkPos.relativeToAbsolute(cx, x), - ChunkPos.relativeToAbsolute(cy, y), - ChunkPos.relativeToAbsolute(cz, z), + ChunkPos.toBlockPosInWorld(cx, x), + ChunkPos.toBlockPosInWorld(cy, y), + ChunkPos.toBlockPosInWorld(cz, z), direction -> { Vector3i nPos = direction.axis().add(finalPos); - Vector3i abs = ChunkPos.relativeToAbsolute(chunkPos, nPos); + Vector3i abs = ChunkPos.toBlockPosInWorld(chunkPos, nPos); final boolean shouldRender = (chunk.isInBound(nPos.x(), nPos.y(), nPos.z()) && chunk.getBlockType(nPos.x(), nPos.y(), nPos.z()).hasSidedTransparency()) || (chunk.world().isBlockLoaded(abs.x(), abs.y(), abs.z()) && - chunk.world().getBlockType(abs.x(), abs.y(), abs.z()).hasSidedTransparency()) || + chunk.world().getBlock(abs).hasSidedTransparency()) || !chunk.world().isBlockLoaded(abs.x(), abs.y(), abs.z()) /* TODO: add method world::tryLoading() */; return !shouldRender; } diff --git a/modules/freeworld.client/src/main/java/freeworld/client/render/world/entity/CubeEntityRenderer.java b/modules/freeworld.client/src/main/java/freeworld/client/render/world/entity/CubeEntityRenderer.java index 6793c42..b359b32 100644 --- a/modules/freeworld.client/src/main/java/freeworld/client/render/world/entity/CubeEntityRenderer.java +++ b/modules/freeworld.client/src/main/java/freeworld/client/render/world/entity/CubeEntityRenderer.java @@ -29,7 +29,7 @@ public CubeEntityRenderer(Freeworld client) { @Override public void render(GLStateMgr gl, double partialTick, Matrix4f positionMatrix, CubeEntity entity) { - RenderSystem.useProgram(client.gameRenderer().positionColorProgram()); + RenderSystem.useProgram(context.gameRenderer().positionColorProgram()); Tessellator t = Tessellator.getInstance(); t.begin(GLDrawMode.TRIANGLES); float x0 = -0.5f; diff --git a/modules/freeworld.client/src/main/java/freeworld/client/render/world/entity/EntityRenderer.java b/modules/freeworld.client/src/main/java/freeworld/client/render/world/entity/EntityRenderer.java index 6ef5e2a..21ce11c 100644 --- a/modules/freeworld.client/src/main/java/freeworld/client/render/world/entity/EntityRenderer.java +++ b/modules/freeworld.client/src/main/java/freeworld/client/render/world/entity/EntityRenderer.java @@ -20,14 +20,14 @@ * @since 0.1.0 */ public abstract class EntityRenderer { - protected final Freeworld client; + protected final Freeworld context; - protected EntityRenderer(Freeworld client) { - this.client = client; + protected EntityRenderer(Freeworld context) { + this.context = context; } public interface Factory { - EntityRenderer create(Freeworld client); + EntityRenderer create(Freeworld context); } public abstract void render(GLStateMgr gl, double partialTick, Matrix4f positionMatrix, T entity); diff --git a/modules/freeworld.client/src/main/java/freeworld/client/render/world/entity/EntityRenderers.java b/modules/freeworld.client/src/main/java/freeworld/client/render/world/entity/EntityRenderers.java index 88f0529..30b2819 100644 --- a/modules/freeworld.client/src/main/java/freeworld/client/render/world/entity/EntityRenderers.java +++ b/modules/freeworld.client/src/main/java/freeworld/client/render/world/entity/EntityRenderers.java @@ -10,20 +10,21 @@ package freeworld.client.render.world.entity; -import freeworld.registry.MappedRegistry; -import freeworld.registry.Registries; -import freeworld.registry.Registry; -import freeworld.util.Identifier; +import freeworld.client.Freeworld; import freeworld.world.entity.Entity; import freeworld.world.entity.EntityType; import freeworld.world.entity.EntityTypes; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + /** * @author squid233 * @since 0.1.0 */ public final class EntityRenderers { - private static final MappedRegistry> REGISTRY = new MappedRegistry<>(Identifier.ofBuiltin("entity_renderer")); + private static final Map, EntityRenderer.Factory> factoryMap = new HashMap<>(); private EntityRenderers() { } @@ -32,12 +33,13 @@ public static void bootstrap() { register(EntityTypes.CUBE, CubeEntityRenderer::new); } - @SuppressWarnings("unchecked") public static void register(EntityType entityType, EntityRenderer.Factory renderer) { - Registry.register(REGISTRY, Registries.ENTITY_TYPE.getId(entityType), (EntityRenderer.Factory) renderer); + factoryMap.put(entityType, renderer); } - public static Registry> registry() { - return REGISTRY; + public static Map, EntityRenderer> loadRenderers(Freeworld context) { + final Map, EntityRenderer> renderers = HashMap.newHashMap(factoryMap.size()); + factoryMap.forEach((entityType, factory) -> renderers.put(entityType, factory.create(context))); + return Collections.unmodifiableMap(renderers); } } diff --git a/modules/freeworld.core/src/main/java/freeworld/registry/Registries.java b/modules/freeworld.core/src/main/java/freeworld/registry/Registries.java index 6af0cd9..cd9e093 100644 --- a/modules/freeworld.core/src/main/java/freeworld/registry/Registries.java +++ b/modules/freeworld.core/src/main/java/freeworld/registry/Registries.java @@ -14,6 +14,7 @@ import freeworld.world.block.BlockType; import freeworld.world.block.BlockTypes; import freeworld.world.entity.EntityType; +import freeworld.world.entity.EntityTypes; /** * @author squid233 @@ -21,7 +22,7 @@ */ public final class Registries { public static final DefaultedRegistry BLOCK_TYPE = new DefaultedRegistry<>(Identifier.ofBuiltin("block_type"), () -> BlockTypes.AIR); - public static final MappedRegistry ENTITY_TYPE = new MappedRegistry<>(Identifier.ofBuiltin("entity_type")); + public static final DefaultedRegistry> ENTITY_TYPE = new DefaultedRegistry<>(Identifier.ofBuiltin("entity_type"), () -> EntityTypes.CUBE); private Registries() { } diff --git a/modules/freeworld.core/src/main/java/freeworld/util/math/ChunkPos.java b/modules/freeworld.core/src/main/java/freeworld/util/math/ChunkPos.java index 5927875..9a366bf 100644 --- a/modules/freeworld.core/src/main/java/freeworld/util/math/ChunkPos.java +++ b/modules/freeworld.core/src/main/java/freeworld/util/math/ChunkPos.java @@ -18,23 +18,23 @@ * @since 0.1.0 */ public final class ChunkPos { - public static int relativeToAbsolute(int chunkPos, int relativePos) { - return chunkPos * Chunk.SIZE + relativePos; + public static int toBlockPosInWorld(int blockPosInChunk, int chunkPos) { + return blockPosInChunk * Chunk.SIZE + chunkPos; } - public static Vector3i relativeToAbsolute(Vector3i chunkPos, Vector3i relativePos) { - return chunkPos.mul(Chunk.SIZE).add(relativePos); + public static Vector3i toBlockPosInWorld(Vector3i blockPosInChunk, Vector3i chunkPos) { + return blockPosInChunk.mul(Chunk.SIZE).add(chunkPos); } - public static int absoluteToRelative(int absolutePos) { - return Math.floorMod(absolutePos, Chunk.SIZE); + public static int toBlockPosInChunk(int blockPosInWorld) { + return Math.floorMod(blockPosInWorld, Chunk.SIZE); } - public static int absoluteToChunk(int absolutePos) { - return Math.floorDiv(absolutePos, Chunk.SIZE); + public static int toChunkPos(int blockPos) { + return Math.floorDiv(blockPos, Chunk.SIZE); } - public static Vector3i absoluteToChunk(Vector3i absolutePos) { - return absolutePos.floorDiv(Chunk.SIZE); + public static Vector3i toChunkPos(Vector3i blockPos) { + return blockPos.floorDiv(Chunk.SIZE); } } diff --git a/modules/freeworld.core/src/main/java/freeworld/world/World.java b/modules/freeworld.core/src/main/java/freeworld/world/World.java index 8b52938..0be0a86 100644 --- a/modules/freeworld.core/src/main/java/freeworld/world/World.java +++ b/modules/freeworld.core/src/main/java/freeworld/world/World.java @@ -10,25 +10,21 @@ package freeworld.world; -import freeworld.math.Vector2d; import freeworld.math.Vector3d; import freeworld.math.Vector3i; import freeworld.util.Int3Consumer; import freeworld.util.math.ChunkPos; -import freeworld.util.math.MathUtil; import freeworld.world.block.BlockType; import freeworld.world.block.BlockTypes; import freeworld.world.chunk.Chunk; -import freeworld.world.entity.CubeEntity; import freeworld.world.entity.Entity; import freeworld.world.entity.EntityType; -import freeworld.world.entity.PlayerEntity; +import freeworld.world.entity.player.PlayerEntity; import freeworld.world.entity.system.MotionSystem; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; /** @@ -38,7 +34,6 @@ public final class World { public static final int TICKING_RADIUS = 5; public final Map chunks = new ConcurrentHashMap<>(2048); - private final List entities = new ArrayList<>(); private final List players = new ArrayList<>(); private final MotionSystem motionSystem = new MotionSystem(); private final List listeners = new ArrayList<>(); @@ -49,7 +44,7 @@ public World(String name, long seed) { } public static void forInChunkRange(Entity player, int chunkRadius, Int3Consumer consumer) { - Vector3i chunkPos = ChunkPos.absoluteToChunk(player.position().toVector3iFloor()); + Vector3i chunkPos = player.chunkPos(); int minX = chunkPos.x() - chunkRadius; int maxX = chunkPos.x() + chunkRadius; int minY = chunkPos.y() - chunkRadius; @@ -71,27 +66,19 @@ public void addListener(WorldListener listener) { public void tick() { motionSystem.process(this, players); - motionSystem.process(this, entities); - // TODO: test - for (Entity entity : entities) { - if (entity instanceof CubeEntity cubeEntity) { - cubeEntity.rotation = new Vector2d(0.0, cubeEntity.rotation().y() + Math.random() * 2 - 1); - cubeEntity.acceleration = MathUtil.moveRelative( - 0.0, cubeEntity.onGround() && Math.random() > 0.5 ? 0.5 : 0.0, 1.0, - cubeEntity.rotation().y(), - cubeEntity.onGround() ? 0.1 : 0.02 - ); - } + for (PlayerEntity player : players) { + forInChunkRange(player, TICKING_RADIUS, (x, y, z) -> getOrCreateChunk(x, y, z).tick()); } } public T createEntity(EntityType type, Vector3d position) { - final T entity = type.factory().create(this, UUID.randomUUID()); - entity.init(position); + final T entity = type.factory().create(this); + entity.setPosition(position); if (entity instanceof PlayerEntity player) { players.add(player); } else { - entities.add(entity); + Vector3i chunkPos = entity.chunkPos(); + getOrCreateChunk(chunkPos.x(), chunkPos.y(), chunkPos.z()).addEntity(entity); } return entity; } @@ -102,9 +89,9 @@ public boolean isChunkLoaded(int x, int y, int z) { public boolean isBlockLoaded(int x, int y, int z) { return isChunkLoaded( - ChunkPos.absoluteToChunk(x), - ChunkPos.absoluteToChunk(y), - ChunkPos.absoluteToChunk(z) + ChunkPos.toChunkPos(x), + ChunkPos.toChunkPos(y), + ChunkPos.toChunkPos(z) ); } @@ -125,31 +112,35 @@ public Chunk getChunk(int x, int y, int z) { public Chunk getChunkByAbsolutePos(int x, int y, int z) { return getChunk( - ChunkPos.absoluteToChunk(x), - ChunkPos.absoluteToChunk(y), - ChunkPos.absoluteToChunk(z) + ChunkPos.toChunkPos(x), + ChunkPos.toChunkPos(y), + ChunkPos.toChunkPos(z) ); } - public BlockType getBlockType(int x, int y, int z) { + public BlockType getBlock(int x, int y, int z) { final Chunk chunk = getChunkByAbsolutePos(x, y, z); if (chunk != null) { return chunk.getBlockType( - ChunkPos.absoluteToRelative(x), - ChunkPos.absoluteToRelative(y), - ChunkPos.absoluteToRelative(z) + ChunkPos.toBlockPosInChunk(x), + ChunkPos.toBlockPosInChunk(y), + ChunkPos.toBlockPosInChunk(z) ); } return BlockTypes.AIR; } - public void setBlockType(int x, int y, int z, BlockType blockType) { + public BlockType getBlock(Vector3i pos) { + return getBlock(pos.x(), pos.y(), pos.z()); + } + + public void setBlock(int x, int y, int z, BlockType blockType) { final Chunk chunk = getChunkByAbsolutePos(x, y, z); if (chunk != null) { chunk.setBlockType( - ChunkPos.absoluteToRelative(x), - ChunkPos.absoluteToRelative(y), - ChunkPos.absoluteToRelative(z), + ChunkPos.toBlockPosInChunk(x), + ChunkPos.toBlockPosInChunk(y), + ChunkPos.toBlockPosInChunk(z), blockType ); for (WorldListener listener : listeners) { @@ -162,7 +153,7 @@ public long seed() { return seed; } - public List entities() { - return entities; + public MotionSystem motionSystem() { + return motionSystem; } } diff --git a/modules/freeworld.core/src/main/java/freeworld/world/chunk/Chunk.java b/modules/freeworld.core/src/main/java/freeworld/world/chunk/Chunk.java index dc23873..926bdba 100644 --- a/modules/freeworld.core/src/main/java/freeworld/world/chunk/Chunk.java +++ b/modules/freeworld.core/src/main/java/freeworld/world/chunk/Chunk.java @@ -10,13 +10,19 @@ package freeworld.world.chunk; +import freeworld.math.Vector2d; import freeworld.util.math.ChunkPos; +import freeworld.util.math.MathUtil; import freeworld.util.math.SimplexNoiseUtil; import freeworld.world.World; import freeworld.world.block.BlockType; import freeworld.world.block.BlockTypes; +import freeworld.world.entity.CubeEntity; +import freeworld.world.entity.Entity; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.StringJoiner; /** @@ -40,6 +46,7 @@ public class Chunk { private final int height; private final int depth; private final BlockType[] blocks; + private final List entities = new ArrayList<>(); public Chunk(World world, int x, int y, int z) { this.world = world; @@ -59,14 +66,37 @@ public Chunk(World world, int x, int y, int z) { Arrays.fill(blocks, BlockTypes.AIR); } + public void tick() { + world.motionSystem().process(world, entities); + // TODO: test + for (Entity entity : entities) { + if (entity instanceof CubeEntity cubeEntity) { + cubeEntity.rotation = new Vector2d(0.0, cubeEntity.rotation().y() + Math.random() * 2 - 1); + cubeEntity.acceleration = MathUtil.moveRelative( + 0.0, cubeEntity.onGround() && Math.random() > 0.5 ? 0.5 : 0.0, 1.0, + cubeEntity.rotation().y(), + cubeEntity.onGround() ? 0.1 : 0.02 + ); + } + } + } + + public void addEntity(Entity entity) { + entities.add(entity); + } + + public void removeEntity(Entity entity) { + entities.remove(entity); + } + public void generateTerrain() { for (int bx = 0; bx < width; bx++) { for (int bz = 0; bz < depth; bz++) { - final int absX = ChunkPos.relativeToAbsolute(x, bx); - final int absZ = ChunkPos.relativeToAbsolute(z, bz); + final int absX = ChunkPos.toBlockPosInWorld(x, bx); + final int absZ = ChunkPos.toBlockPosInWorld(z, bz); final float heightmap = SimplexNoiseUtil.sumOctave(8, absX, absZ, world.seed() & 0xff, (world.seed() >> 8) & 0xff, 0.2f, 0.003f, -64.0f, 64.0f); for (int by = 0; by < height; by++) { - final int absY = ChunkPos.relativeToAbsolute(y, by); + final int absY = ChunkPos.toBlockPosInWorld(y, by); if (absY < heightmap - 3) { setBlockType(bx, by, bz, BlockTypes.STONE); } else if (absY < heightmap - 1) { @@ -107,6 +137,10 @@ public World world() { return world; } + public List entities() { + return entities; + } + public int x() { return x; } diff --git a/modules/freeworld.core/src/main/java/freeworld/world/entity/CubeEntity.java b/modules/freeworld.core/src/main/java/freeworld/world/entity/CubeEntity.java index b85c410..014ecdf 100644 --- a/modules/freeworld.core/src/main/java/freeworld/world/entity/CubeEntity.java +++ b/modules/freeworld.core/src/main/java/freeworld/world/entity/CubeEntity.java @@ -12,14 +12,12 @@ import freeworld.world.World; -import java.util.UUID; - /** * @author squid233 * @since 0.1.0 */ public class CubeEntity extends Entity { - public CubeEntity(World world, UUID uuid) { - super(world, uuid, EntityTypes.CUBE); + public CubeEntity(World world) { + super(EntityTypes.CUBE, world); } } diff --git a/modules/freeworld.core/src/main/java/freeworld/world/entity/Entity.java b/modules/freeworld.core/src/main/java/freeworld/world/entity/Entity.java index 22982c4..15429e3 100644 --- a/modules/freeworld.core/src/main/java/freeworld/world/entity/Entity.java +++ b/modules/freeworld.core/src/main/java/freeworld/world/entity/Entity.java @@ -10,9 +10,12 @@ package freeworld.world.entity; +import freeworld.math.Maths; import freeworld.math.Vector2d; import freeworld.math.Vector3d; +import freeworld.math.Vector3i; import freeworld.util.math.AABBox; +import freeworld.util.math.ChunkPos; import freeworld.world.World; import java.util.UUID; @@ -23,30 +26,31 @@ */ public class Entity { private final World world; - private final UUID uuid; - private final EntityType entityType; + private final EntityType type; + private final UUID uuid = UUID.randomUUID(); public Vector3d acceleration = Vector3d.ZERO; + private Vector3i blockPos = Vector3i.ZERO; public AABBox boundingBox; - public Vector3d eyePosition; + private Vector3i chunkPos = Vector3i.ZERO; + private final Vector3d dimension; + public double eyeHeight; public boolean flying = false; public boolean onGround = false; private Vector3d previousPosition = Vector3d.ZERO; private Vector3d position = Vector3d.ZERO; - private Vector3d interpolatedPosition = Vector3d.ZERO; public Vector2d rotation = Vector2d.ZERO; public Vector3d velocity = Vector3d.ZERO; - public Entity(World world, UUID uuid, EntityType entityType) { + public Entity(EntityType type, World world) { this.world = world; - this.uuid = uuid; - this.entityType = entityType; - this.eyePosition = entityType.eyePosition(); + this.type = type; + this.dimension = type.dimension(); + this.eyeHeight = getEyeHeight(dimension); + setPosition(new Vector3d(0.0, 0.0, 0.0)); } - public static AABBox boundingBox( - Vector3d position, - Vector3d dimension - ) { + private AABBox calculateBoundingBox() { + // TODO: use EntityDimension final double hw = dimension.x() * 0.5; final double hd = dimension.z() * 0.5; return new AABBox( @@ -59,9 +63,12 @@ public static AABBox boundingBox( ); } - public final void init(Vector3d position) { - this.position = position; - this.boundingBox = boundingBox(position, entityType.dimension()); + public double getEyeHeight(Vector3d dimension) { + return dimension.y() * 0.9; + } + + public double getEyeHeight() { + return getEyeHeight(dimension); } public void updatePreviousPosition() { @@ -69,11 +76,36 @@ public void updatePreviousPosition() { } public void setPosition(Vector3d position) { - this.position = position; + setPos(position); + setBoundingBox(calculateBoundingBox()); + } + + public void setPos(Vector3d pos) { + if (!this.position.equals(pos)) { + this.position = pos; + int x = Maths.floorToInt(this.position.x()); + int y = Maths.floorToInt(this.position.y()); + int z = Maths.floorToInt(this.position.z()); + if (x != this.blockPos.x() || y != this.blockPos.y() || z != this.blockPos.z()) { + this.blockPos = new Vector3i(x, y, z); + Vector3i chunkPos = ChunkPos.toChunkPos(this.blockPos); + if (!this.chunkPos.equals(chunkPos)) { + this.chunkPos = chunkPos; + } + } + } + } + + public void setBoundingBox(AABBox boundingBox) { + this.boundingBox = boundingBox; } - public void interpolatePosition(double partialTick) { - interpolatedPosition = previousPosition.lerp(position, partialTick); + public Vector3d interpolatedPosition(double partialTick) { + return previousPosition.lerp(position, partialTick); + } + + public Vector3d getCameraPos(double partialTick) { + return interpolatedPosition(partialTick).add(0.0, getEyeHeight(), 0.0); } public World world() { @@ -84,20 +116,24 @@ public UUID uuid() { return uuid; } - public EntityType entityType() { - return entityType; + public EntityType type() { + return type; } public Vector3d acceleration() { return acceleration; } + public Vector3i blockPos() { + return blockPos; + } + public AABBox boundingBox() { return boundingBox; } - public Vector3d eyePosition() { - return eyePosition; + public Vector3i chunkPos() { + return chunkPos; } public boolean flying() { @@ -116,10 +152,6 @@ public Vector3d position() { return position; } - public Vector3d interpolatedPosition() { - return interpolatedPosition; - } - public Vector2d rotation() { return rotation; } diff --git a/modules/freeworld.core/src/main/java/freeworld/world/entity/EntityType.java b/modules/freeworld.core/src/main/java/freeworld/world/entity/EntityType.java index 70604e1..990866b 100644 --- a/modules/freeworld.core/src/main/java/freeworld/world/entity/EntityType.java +++ b/modules/freeworld.core/src/main/java/freeworld/world/entity/EntityType.java @@ -14,7 +14,6 @@ import freeworld.world.World; import java.util.Objects; -import java.util.UUID; /** * @author squid233 @@ -23,31 +22,39 @@ public class EntityType { private final Factory factory; private final Vector3d dimension; - private final Vector3d eyePosition; - public EntityType(Settings settings, Factory factory) { + private EntityType(Factory factory, Vector3d dimension) { this.factory = factory; - this.dimension = Objects.requireNonNull(settings.dimension); - this.eyePosition = Objects.requireNonNull(settings.eyePosition); + this.dimension = dimension; } @FunctionalInterface public interface Factory { - T create(World world, UUID uuid); + T create(World world); } - public static final class Settings { - private Vector3d dimension; - private Vector3d eyePosition = new Vector3d(0.0, 0.5, 0.0); + public static Builder builder(Factory factory) { + return new Builder<>(factory); + } + + public static final class Builder { + private final Factory factory; + private Vector3d dimension = new Vector3d(0.6, 1.8, 0.6); + + private Builder(Factory factory) { + this.factory = factory; + } - public Settings dimension(Vector3d dimension) { + public Builder dimension(Vector3d dimension) { this.dimension = dimension; return this; } - public Settings eyePosition(Vector3d eyePosition) { - this.eyePosition = eyePosition; - return this; + public EntityType build() { + return new EntityType<>( + factory, + Objects.requireNonNull(dimension) + ); } } @@ -58,8 +65,4 @@ public Factory factory() { public Vector3d dimension() { return dimension; } - - public Vector3d eyePosition() { - return eyePosition; - } } diff --git a/modules/freeworld.core/src/main/java/freeworld/world/entity/EntityTypes.java b/modules/freeworld.core/src/main/java/freeworld/world/entity/EntityTypes.java index aaa8709..3b177a3 100644 --- a/modules/freeworld.core/src/main/java/freeworld/world/entity/EntityTypes.java +++ b/modules/freeworld.core/src/main/java/freeworld/world/entity/EntityTypes.java @@ -14,23 +14,24 @@ import freeworld.registry.Registries; import freeworld.registry.Registry; import freeworld.math.Vector3d; +import freeworld.world.entity.player.PlayerEntity; /** * @author squid233 * @since 0.1.0 */ public final class EntityTypes { - public static final EntityType PLAYER = register("player", new EntityType<>(new EntityType.Settings().dimension(new Vector3d(0.6, 1.8, 0.6)).eyePosition(new Vector3d(0.0, 1.62, 0.0)), PlayerEntity::new)); + public static final EntityType PLAYER = register("player", EntityType.builder(PlayerEntity::new).dimension(new Vector3d(0.6, 1.8, 0.6))); /** * A cube entity is for test. */ - public static final EntityType CUBE = register("cube", new EntityType<>(new EntityType.Settings().dimension(new Vector3d(1.0)), CubeEntity::new)); + public static final EntityType CUBE = register("cube", EntityType.builder(CubeEntity::new).dimension(new Vector3d(1.0))); private EntityTypes() { } - private static EntityType register(String name, EntityType entityType) { - return Registry.register(Registries.ENTITY_TYPE, Identifier.ofBuiltin(name), entityType); + private static EntityType register(String name, EntityType.Builder entityType) { + return Registry.register(Registries.ENTITY_TYPE, Identifier.ofBuiltin(name), entityType.build()); } public static void bootstrap() { diff --git a/modules/freeworld.core/src/main/java/freeworld/world/entity/PlayerEntity.java b/modules/freeworld.core/src/main/java/freeworld/world/entity/player/PlayerEntity.java similarity index 85% rename from modules/freeworld.core/src/main/java/freeworld/world/entity/PlayerEntity.java rename to modules/freeworld.core/src/main/java/freeworld/world/entity/player/PlayerEntity.java index c13b760..a0273e7 100644 --- a/modules/freeworld.core/src/main/java/freeworld/world/entity/PlayerEntity.java +++ b/modules/freeworld.core/src/main/java/freeworld/world/entity/player/PlayerEntity.java @@ -8,13 +8,13 @@ * only version 2.1 of the License. */ -package freeworld.world.entity; +package freeworld.world.entity.player; import freeworld.world.World; import freeworld.world.block.BlockType; import freeworld.world.block.BlockTypes; - -import java.util.UUID; +import freeworld.world.entity.Entity; +import freeworld.world.entity.EntityTypes; /** * @author squid233 @@ -35,8 +35,8 @@ public class PlayerEntity extends Entity { }; private int selectedHotBar = 0; - public PlayerEntity(World world, UUID uuid) { - super(world, uuid, EntityTypes.PLAYER); + public PlayerEntity(World world) { + super(EntityTypes.PLAYER, world); } public void selectHotBar(int index) { diff --git a/modules/freeworld.core/src/main/java/freeworld/world/entity/system/MotionSystem.java b/modules/freeworld.core/src/main/java/freeworld/world/entity/system/MotionSystem.java index 67ff32e..bc48f7c 100644 --- a/modules/freeworld.core/src/main/java/freeworld/world/entity/system/MotionSystem.java +++ b/modules/freeworld.core/src/main/java/freeworld/world/entity/system/MotionSystem.java @@ -13,7 +13,6 @@ import freeworld.math.Maths; import freeworld.math.Vector3d; import freeworld.util.math.AABBox; -import freeworld.util.math.ChunkPos; import freeworld.world.World; import freeworld.world.block.BlockType; import freeworld.world.entity.Entity; @@ -45,21 +44,16 @@ public void process(World world, List entities) { final int x0 = Maths.floorToInt(range.minX()); final int y0 = Maths.floorToInt(range.minY()); final int z0 = Maths.floorToInt(range.minZ()); - final int x1 = Maths.ceilToInt(range.maxX() + 1.0); - final int y1 = Maths.ceilToInt(range.maxY() + 1.0); - final int z1 = Maths.ceilToInt(range.maxZ() + 1.0); - for (int x = x0; x < x1; x++) { - for (int y = y0; y < y1; y++) { - for (int z = z0; z < z1; z++) { + final int x1 = Maths.floorToInt(range.maxX()); + final int y1 = Maths.floorToInt(range.maxY()); + final int z1 = Maths.floorToInt(range.maxZ()); + for (int x = x0; x <= x1; x++) { + for (int y = y0; y <= y1; y++) { + for (int z = z0; z <= z1; z++) { if (!world.isBlockLoaded(x, y, z)) { - world.getOrCreateChunk( - ChunkPos.absoluteToChunk(x), - ChunkPos.absoluteToChunk(y), - ChunkPos.absoluteToChunk(z) - ); continue; } - final BlockType blockType = world.getBlockType(x, y, z); + final BlockType blockType = world.getBlock(x, y, z); if (blockType.air()) { continue; } @@ -101,7 +95,6 @@ public void process(World world, List entities) { entity.updatePreviousPosition(); entity.setPosition(entity.position().add(moveX, moveY, moveZ)); - entity.boundingBox = Entity.boundingBox(entity.position(), entity.boundingBox().dimension()); if (entity.flying()) { entity.velocity = Vector3d.ZERO; diff --git a/modules/freeworld.core/src/main/java/module-info.java b/modules/freeworld.core/src/main/java/module-info.java index 8cf6a2b..8229ac7 100644 --- a/modules/freeworld.core/src/main/java/module-info.java +++ b/modules/freeworld.core/src/main/java/module-info.java @@ -25,6 +25,7 @@ exports freeworld.world.block; exports freeworld.world.chunk; exports freeworld.world.entity; + exports freeworld.world.entity.player; exports freeworld.world.entity.system; requires transitive freeworld.math; diff --git a/modules/freeworld.math/src/main/java/freeworld/math/Vector3d.java b/modules/freeworld.math/src/main/java/freeworld/math/Vector3d.java index 7ec28ff..b5ce9c1 100644 --- a/modules/freeworld.math/src/main/java/freeworld/math/Vector3d.java +++ b/modules/freeworld.math/src/main/java/freeworld/math/Vector3d.java @@ -45,6 +45,7 @@ public Vector3f toVector3f() { return new Vector3f((float) x, (float) y, (float) z); } + @Deprecated public Vector3i toVector3iFloor() { return new Vector3i(Maths.floorToInt(x), Maths.floorToInt(y), Maths.floorToInt(z)); }