Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infinite world #25

Merged
merged 24 commits into from
Jan 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
959313e
Infinite world: First attempt.
Unarelith Jan 15, 2020
0af1506
[ServerWorld] New function added to send spawn data to connecting cli…
Unarelith Jan 16, 2020
c7556e4
[ClientWorld|ServerWorld] Spawn data sending is now working.
Unarelith Jan 16, 2020
b1ad2a9
[World] Small patch. Fixes player collisions and block placing.
Unarelith Jan 16, 2020
4f951fc
[ClientWorld] Now waiting all neighbours of a chunk before updating/d…
Unarelith Jan 16, 2020
bebc299
[ServerChunk] 'update' renamed into 'updateLights'.
Unarelith Jan 16, 2020
01e34d1
Removed useless code.
Unarelith Jan 16, 2020
d932c66
Small tweaks.
Unarelith Jan 17, 2020
57911d6
Attempting to improve light propagation.
Unarelith Jan 17, 2020
061ead9
Reverting last commit.
Unarelith Jan 17, 2020
515025c
Almost fixed the lighting issue, found the problem.
Unarelith Jan 17, 2020
8e945ee
Lighting issues finally fixed. Yay.
Unarelith Jan 17, 2020
9ee94ee
[BlockInfoWidget] Removed coordinates display.
Unarelith Jan 17, 2020
85625ec
[ServerWorld|ChunkLightmap|ServerChunk] Removed useless updateLight()…
Unarelith Jan 19, 2020
3dab12e
[ServerWorld] First attempt to send chunks depending on player position.
Unarelith Jan 19, 2020
b919376
[ServerWorld] Second client can now receive chunks, but it's reaaaall…
Unarelith Jan 19, 2020
53b518b
Multiplayer infinite world: OK using 'ChunkRequest' packet.
Unarelith Jan 20, 2020
6aa7ab7
[World] Furnace crash fixed. [ClientWorld] Small fix.
Unarelith Jan 20, 2020
3fae19d
[ServerWorld] Debug removed.
Unarelith Jan 20, 2020
92b5295
Last lighting issue almost fixed.
Unarelith Jan 20, 2020
034ad32
[DebugOverlay] Now showing loaded chunks count.
Unarelith Jan 20, 2020
9a82a58
[ServerWorld] Tree gen fixed.
Unarelith Jan 21, 2020
42275d2
[TerrainGenerator] Fixed small lighting issue.
Unarelith Jan 21, 2020
e5145fe
[ClientWorld] Now deleting chunks that are too far.
Unarelith Jan 21, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion client/include/hud/DebugOverlay.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,19 @@
#include "Text.hpp"

class ClientPlayer;
class ClientWorld;

class DebugOverlay : public gk::Transformable, public gk::Drawable {
public:
DebugOverlay(const ClientPlayer &player);
DebugOverlay(const ClientPlayer &player, const ClientWorld &world);

void update();

private:
void draw(gk::RenderTarget &target, gk::RenderStates states) const override;

const ClientPlayer &m_player;
const ClientWorld &m_world;

Text m_versionText;
Text m_positionText;
Expand Down
1 change: 0 additions & 1 deletion client/include/hud/HUD.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class HUD : public gk::Transformable, public gk::Drawable {

Hotbar m_hotbar;

glm::vec4 m_selectedBlock{0, 0, 0, -1};
BlockCursor m_blockCursor;
Crosshair m_crosshair;

Expand Down
2 changes: 1 addition & 1 deletion client/include/world/ChunkBuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class ChunkBuilder {
Torch
};

float getLightForVertex(Light light, u8 x, u8 y, u8 z, u8 i, u8 j, const glm::vec3 &normal, const ClientChunk &chunk);
u8 getLightForVertex(Light light, u8 x, u8 y, u8 z, u8 i, u8 j, const glm::vec3 &normal, const ClientChunk &chunk);

std::array<std::vector<gk::Vertex>, layers> m_vertices;

Expand Down
6 changes: 6 additions & 0 deletions client/include/world/ClientChunk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ class ClientChunk : public Chunk {
bool hasBeenRequested() const { return m_hasBeenRequested; }
void setHasBeenRequested(bool hasBeenRequested) { m_hasBeenRequested = hasBeenRequested; }

bool isTooFar() const { return m_isTooFar; }
void setTooFar(bool isTooFar) { m_isTooFar = isTooFar; }

bool areAllNeighboursTooFar() const;

private:
gk::Texture &m_texture;

Expand All @@ -42,6 +47,7 @@ class ClientChunk : public Chunk {
std::array<std::size_t, ChunkBuilder::layers> m_verticesCount{};

bool m_hasBeenRequested = false;
bool m_isTooFar = false;
};

#endif // CLIENTCHUNK_HPP_
28 changes: 17 additions & 11 deletions client/include/world/ClientWorld.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#ifndef CLIENTWORLD_HPP_
#define CLIENTWORLD_HPP_

#include <memory>
#include <unordered_map>

#include "ClientChunk.hpp"
#include "Network.hpp"
Expand All @@ -23,33 +23,39 @@
class ClientCommandHandler;

class ClientWorld : public World, public gk::Drawable {
using ChunkMap = std::unordered_map<gk::Vector3i, std::unique_ptr<ClientChunk>>;

public:
ClientWorld();

void init(float playerX, float playerY, float playerZ);
void update();
void sendChunkRequests();

void receiveChunkData(sf::Packet &packet);
void removeChunk(ChunkMap::iterator &it);

// FIXME: Duplicated with ServerWorld
ClientChunk *getChunk(int cx, int cy, int cz) const;
BlockData *getBlockData(int x, int y, int z) const override;

// FIXME: Duplicated with ServerWorld
u16 getBlock(int x, int y, int z) const override;
void setBlock(int x, int y, int z, u16 id) override;
u16 getData(int x, int y, int z) const override;
void setData(int x, int y, int z, u16 id) override;
Chunk *getChunk(int cx, int cy, int cz) const override;

void setClient(ClientCommandHandler &client) { m_client = &client; }

std::size_t loadedChunkCount() const { return m_chunks.size(); }

private:
void createChunkNeighbours(ClientChunk *chunk);

void draw(gk::RenderTarget &target, gk::RenderStates states) const override;

std::vector<std::unique_ptr<ClientChunk>> m_chunks;
ChunkMap m_chunks;

gk::Texture &m_texture;

ClientCommandHandler *m_client = nullptr;

mutable float m_ud = 1000;
mutable s32 m_ux;
mutable s32 m_uy;
mutable s32 m_uz;
};

#endif // CLIENTWORLD_HPP_
7 changes: 5 additions & 2 deletions client/source/core/ClientApplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,11 @@ void ClientApplication::init() {
Registry::setInstance(m_registry);

// m_stateStack.push<TitleScreenState>();
auto &game = m_stateStack.push<GameState>(m_host, m_port);
m_stateStack.push<ServerLoadingState>(game);

m_stateStack.push<GameState>(m_host, m_port);

// auto &game = m_stateStack.push<GameState>(m_host, m_port);
// m_stateStack.push<ServerLoadingState>(game);
}

void ClientApplication::initOpenGL() {
Expand Down
27 changes: 20 additions & 7 deletions client/source/hud/DebugOverlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
#include <sstream>

#include "ClientPlayer.hpp"
#include "ClientWorld.hpp"
#include "Config.hpp"
#include "DebugOverlay.hpp"

DebugOverlay::DebugOverlay(const ClientPlayer &player) : m_player(player) {
DebugOverlay::DebugOverlay(const ClientPlayer &player, const ClientWorld &world)
: m_player(player), m_world(world)
{
setPosition(4, 4, 0);

m_versionText.setText(APP_NAME + std::string(" v0.0.1"));
Expand All @@ -28,14 +31,24 @@ DebugOverlay::DebugOverlay(const ClientPlayer &player) : m_player(player) {
}

void DebugOverlay::update() {
s32 pcx = std::floor(m_player.x() / CHUNK_WIDTH);
s32 pcy = std::floor(m_player.y() / CHUNK_HEIGHT);
s32 pcz = std::floor(m_player.z() / CHUNK_DEPTH);

std::stringstream stream;
stream << "x: " << floorf(m_player.x()) << " | ";
stream << "y: " << floorf(m_player.y()) << " | ";
stream << "z: " << floorf(m_player.z());
stream << "x: " << std::floor(m_player.x()) << " | ";
stream << "y: " << std::floor(m_player.y()) << " | ";
stream << "z: " << std::floor(m_player.z());
stream << '\n';
stream << "rx: " << int(std::floor(m_player.x()) + std::abs(pcx) * CHUNK_WIDTH) % CHUNK_WIDTH << " | ";
stream << "ry: " << int(std::floor(m_player.y()) + std::abs(pcy) * CHUNK_HEIGHT) % CHUNK_HEIGHT << " | ";
stream << "rz: " << int(std::floor(m_player.z()) + std::abs(pcz) * CHUNK_DEPTH) % CHUNK_DEPTH;
stream << '\n';
stream << "cx: " << pcx << " | ";
stream << "cy: " << pcy << " | ";
stream << "cz: " << pcz;
stream << '\n';
stream << "cx: " << floorf(m_player.x() / CHUNK_WIDTH) << " | ";
stream << "cy: " << floorf(m_player.y() / CHUNK_HEIGHT) << " | ";
stream << "cz: " << floorf(m_player.z() / CHUNK_DEPTH);
stream << "Loaded chunks: " << m_world.loadedChunkCount();

m_positionText.setText(stream.str());
}
Expand Down
2 changes: 1 addition & 1 deletion client/source/hud/HUD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ HUD::HUD(ClientPlayer &player, ClientWorld &world, ClientCommandHandler &client)
: m_client(client),
m_hotbar(player.inventory()),
m_blockCursor(player, world, client),
m_debugOverlay(player)
m_debugOverlay(player, world)
{
setScale(GUI_SCALE, GUI_SCALE, 1);

Expand Down
2 changes: 2 additions & 0 deletions client/source/network/ClientCommandHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ void ClientCommandHandler::setupCallbacks() {
m_playerBoxes.at(clientId).setPosition(pos.x, pos.y, pos.z);
m_playerBoxes.at(clientId).setClientID(clientId);
}

m_world.init(pos.x, pos.y, pos.z);
});

m_client.setCommandCallback(Network::Command::BlockGUIData, [this](sf::Packet &packet) {
Expand Down
6 changes: 4 additions & 2 deletions client/source/states/ServerConnectState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ ServerConnectState::ServerConnectState() {
std::cerr << "Error: Invalid server address." << std::endl;
}

auto &game = m_stateStack->push<GameState>(host, port);
m_stateStack->push<ServerLoadingState>(game);
m_stateStack->push<GameState>(host, port);

// auto &game = m_stateStack->push<GameState>(host, port);
// m_stateStack->push<ServerLoadingState>(game);
});

m_cancelButton.setText("Cancel");
Expand Down
4 changes: 0 additions & 4 deletions client/source/states/ServerLoadingState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ ServerLoadingState::ServerLoadingState(GameState &game) : m_game(game) {
m_textShadow.setColor(gk::Color{70, 70, 70, 255});
m_textShadow.setPosition(m_text.getPosition().x + 6, m_text.getPosition().y + 6);

m_game.client().setCommandCallback(Network::Command::WorldSent, [this] (sf::Packet &) {
m_isWorldSent = true;
});

gk::Mouse::setCursorVisible(true);
gk::Mouse::setCursorGrabbed(false);
}
Expand Down
50 changes: 39 additions & 11 deletions client/source/world/ChunkBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,21 @@ inline u8 ChunkBuilder::getAmbientOcclusion(u8 x, u8 y, u8 z, u8 i, u8 j, const
return 3 - (side1 + side2 + corner);
}

inline float ChunkBuilder::getLightForVertex(Light light, u8 x, u8 y, u8 z, u8 i, u8 j, const glm::vec3 &normal, const ClientChunk &chunk) {
inline u8 ChunkBuilder::getLightForVertex(Light light, u8 x, u8 y, u8 z, u8 i, u8 j, const glm::vec3 &normal, const ClientChunk &chunk) {
std::function<s8(const Chunk *chunk, s8, s8, s8)> getLight = [&](const Chunk *chunk, s8 x, s8 y, s8 z) -> s8 {
if(x < 0) return chunk->getSurroundingChunk(0) && chunk->getSurroundingChunk(0)->isInitialized() ? getLight(chunk->getSurroundingChunk(0), x + CHUNK_WIDTH, y, z) : -1;
if(x >= CHUNK_WIDTH) return chunk->getSurroundingChunk(1) && chunk->getSurroundingChunk(1)->isInitialized() ? getLight(chunk->getSurroundingChunk(1), x - CHUNK_WIDTH, y, z) : -1;
if(y < 0) return chunk->getSurroundingChunk(4) && chunk->getSurroundingChunk(4)->isInitialized() ? getLight(chunk->getSurroundingChunk(4), x, y + CHUNK_HEIGHT, z) : -1;
if(y >= CHUNK_HEIGHT) return chunk->getSurroundingChunk(5) && chunk->getSurroundingChunk(5)->isInitialized() ? getLight(chunk->getSurroundingChunk(5), x, y - CHUNK_HEIGHT, z) : -1;
if(z < 0) return chunk->getSurroundingChunk(2) && chunk->getSurroundingChunk(2)->isInitialized() ? getLight(chunk->getSurroundingChunk(2), x, y, z + CHUNK_DEPTH) : -1;
if(z >= CHUNK_DEPTH) return chunk->getSurroundingChunk(3) && chunk->getSurroundingChunk(3)->isInitialized() ? getLight(chunk->getSurroundingChunk(3), x, y, z - CHUNK_DEPTH) : -1;

if (light == Light::Sun)
return chunk->isInitialized() ? chunk->lightmap().getSunlight(x, y, z) : -1;
else
return chunk->isInitialized() ? chunk->lightmap().getTorchlight(x, y, z) : -1;
};

gk::Vector3i offset = getOffsetFromVertex(i, j);

gk::Vector3i minOffset{
Expand All @@ -342,16 +356,30 @@ inline float ChunkBuilder::getLightForVertex(Light light, u8 x, u8 y, u8 z, u8 i
(normal.z != 0) ? offset.z : 0
};

// FIXME: Air blocks have a light level of 0
if (light == Light::Sun)
return (chunk.lightmap().getSunlight(x + minOffset.x, y + offset.y, z + minOffset.z)
+ chunk.lightmap().getSunlight(x + offset.x, y + minOffset.y, z + minOffset.z)
+ chunk.lightmap().getSunlight(x + minOffset.x, y + minOffset.y, z + offset.z)
+ chunk.lightmap().getSunlight(x + offset.x, y + offset.y, z + offset.z)) / 4.0f;
// Get light values for surrounding nodes
s8 lightValues[4] = {
getLight(&chunk, x + minOffset.x, y + offset.y, z + minOffset.z),
getLight(&chunk, x + offset.x, y + minOffset.y, z + minOffset.z),
getLight(&chunk, x + minOffset.x, y + minOffset.y, z + offset.z),
getLight(&chunk, x + offset.x, y + offset.y, z + offset.z),
};

u8 count = 0, total = 0;
for (u8 i = 0 ; i < 4 ; ++i) {
// Fix light approximation
// if (i == 3 && lightValues[i] > lightValues[0] && !lightValues[1] && !lightValues[2])
// continue;

// If the chunk is initialized, add the light value to the total
if (lightValues[i] != -1) {
total += lightValues[i];
++count;
}
}

if (count)
return total / count;
else
return (chunk.lightmap().getTorchlight(x + minOffset.x, y + offset.y, z + minOffset.z)
+ chunk.lightmap().getTorchlight(x + offset.x, y + minOffset.y, z + minOffset.z)
+ chunk.lightmap().getTorchlight(x + minOffset.x, y + minOffset.y, z + offset.z)
+ chunk.lightmap().getTorchlight(x + offset.x, y + offset.y, z + offset.z)) / 4.0f;
return 0;
}

12 changes: 10 additions & 2 deletions client/source/world/ClientChunk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@
#include "ClientChunk.hpp"

void ClientChunk::update() {
if (m_isInitialized && m_hasChanged) {
if (m_lightmap.updateLights() || m_hasChanged) {
m_hasChanged = false;
m_lightmap.updateLights();

m_verticesCount = m_builder.buildChunk(*this, m_vbo);
}
Expand All @@ -41,3 +40,12 @@ void ClientChunk::drawLayer(gk::RenderTarget &target, gk::RenderStates states, u
if(Config::isWireframeModeEnabled) glCheck(glPolygonMode(GL_FRONT_AND_BACK, GL_FILL));
}

bool ClientChunk::areAllNeighboursTooFar() const {
return (!m_surroundingChunks[Chunk::Left] || ((ClientChunk *)m_surroundingChunks[Chunk::Left])->isTooFar())
&& (!m_surroundingChunks[Chunk::Right] || ((ClientChunk *)m_surroundingChunks[Chunk::Right])->isTooFar())
&& (!m_surroundingChunks[Chunk::Front] || ((ClientChunk *)m_surroundingChunks[Chunk::Front])->isTooFar())
&& (!m_surroundingChunks[Chunk::Back] || ((ClientChunk *)m_surroundingChunks[Chunk::Back])->isTooFar())
&& (!m_surroundingChunks[Chunk::Bottom] || ((ClientChunk *)m_surroundingChunks[Chunk::Bottom])->isTooFar())
&& (!m_surroundingChunks[Chunk::Top] || ((ClientChunk *)m_surroundingChunks[Chunk::Top])->isTooFar());
}

23 changes: 12 additions & 11 deletions client/source/world/ClientPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ ClientPlayer *ClientPlayer::s_instance = nullptr;

ClientPlayer::ClientPlayer(gk::Camera &camera) : m_camera(camera) {
// FIXME: Warning: Duplicated in ServerCommandHandler.hpp
m_x = 0;
m_y = 22;
m_z = 20;
m_x = 10;
m_y = 18;
m_z = 12;

m_angleH = 90.0;
m_angleH = -90.0;
m_angleV = 0.01;

m_camera.setPosition(m_x, m_y, m_z);
Expand Down Expand Up @@ -101,7 +101,8 @@ void ClientPlayer::processInputs() {
}

void ClientPlayer::updatePosition(const ClientWorld &world) {
if (!Config::isFlyModeEnabled) {
ClientChunk *chunk = (ClientChunk *)world.getChunkAtBlockPos(m_x, m_y - 0.2, m_z);
if (!Config::isFlyModeEnabled && chunk && chunk->isInitialized()) {
m_velocity.y -= m_gravity; // Gravity

if (m_velocity.y < -m_jumpSpeed) // Jump max accel
Expand Down Expand Up @@ -130,13 +131,13 @@ void ClientPlayer::updatePosition(const ClientWorld &world) {

// FIXME: Use AABB for more precision
void ClientPlayer::checkCollisions(const ClientWorld &world) {
const float CLIENTPLAYER_HEIGHT = 1.8;
float eyeheight = m_y + CLIENTPLAYER_HEIGHT - 1.4;
const float PLAYER_HEIGHT = 1.8;
float eyeheight = m_y + PLAYER_HEIGHT - 1.4;
// testPoint(world, glm::vec3(m_x, m_y, m_z), m_velocity);
testPoint(world, glm::vec3(m_x - 0.2, eyeheight - CLIENTPLAYER_HEIGHT - 0.4, m_z - 0.2), m_velocity);
testPoint(world, glm::vec3(m_x + 0.2, eyeheight - CLIENTPLAYER_HEIGHT - 0.4, m_z - 0.2), m_velocity);
testPoint(world, glm::vec3(m_x - 0.2, eyeheight - CLIENTPLAYER_HEIGHT - 0.4, m_z + 0.2), m_velocity);
testPoint(world, glm::vec3(m_x + 0.2, eyeheight - CLIENTPLAYER_HEIGHT - 0.4, m_z + 0.2), m_velocity);
testPoint(world, glm::vec3(m_x - 0.2, eyeheight - PLAYER_HEIGHT - 0.4, m_z - 0.2), m_velocity);
testPoint(world, glm::vec3(m_x + 0.2, eyeheight - PLAYER_HEIGHT - 0.4, m_z - 0.2), m_velocity);
testPoint(world, glm::vec3(m_x - 0.2, eyeheight - PLAYER_HEIGHT - 0.4, m_z + 0.2), m_velocity);
testPoint(world, glm::vec3(m_x + 0.2, eyeheight - PLAYER_HEIGHT - 0.4, m_z + 0.2), m_velocity);
testPoint(world, glm::vec3(m_x - 0.2, eyeheight - 0.4, m_z - 0.2), m_velocity);
testPoint(world, glm::vec3(m_x + 0.2, eyeheight - 0.4, m_z - 0.2), m_velocity);
testPoint(world, glm::vec3(m_x - 0.2, eyeheight - 0.4, m_z + 0.2), m_velocity);
Expand Down
Loading