mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-06-17 16:17:02 +08:00
feat(world): add day/night cycle with server tick system
This commit is contained in:
@@ -19,7 +19,7 @@ void main(void) {
|
|||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 lightDir = normalize(sunlightDir);
|
vec3 lightDir = normalize(-sunlightDir);
|
||||||
|
|
||||||
vec3 ambient = ambientStrength * sunlightColor;
|
vec3 ambient = ambientStrength * sunlightColor;
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
out vec4 frag_color;
|
out vec4 frag_color;
|
||||||
|
|
||||||
|
uniform vec3 color;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
|
|
||||||
frag_color = vec4(0.529, 0.808, 0.922, 1.0);
|
frag_color = vec4(color, 1.0);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -44,8 +44,11 @@ private:
|
|||||||
bool m_need_save_config = false;
|
bool m_need_save_config = false;
|
||||||
bool m_gen_thread_running = true;
|
bool m_gen_thread_running = true;
|
||||||
int m_theme = 0;
|
int m_theme = 0;
|
||||||
|
int m_pre_set_day_tick = 0;
|
||||||
|
int m_pre_set_tick_speed = 0;
|
||||||
void show_about_table_bar();
|
void show_about_table_bar();
|
||||||
void show_biome_table_bar();
|
void show_biome_table_bar();
|
||||||
|
void show_time_table_bar();
|
||||||
void show_cave_table_bar();
|
void show_cave_table_bar();
|
||||||
void show_river_table_bar();
|
void show_river_table_bar();
|
||||||
void show_settings_tab_item();
|
void show_settings_tab_item();
|
||||||
|
|||||||
9
include/Cubed/gameplay/game_time.hpp
Normal file
9
include/Cubed/gameplay/game_time.hpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
using TickType = long long;
|
||||||
|
|
||||||
|
constexpr int DEFAULT_PER_TICK_TIME = 50;
|
||||||
|
|
||||||
|
constexpr TickType DAY_TIME = 24000;
|
||||||
|
|
||||||
|
constexpr TickType PER_HOUR = 1000;
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "Cubed/AABB.hpp"
|
#include "Cubed/AABB.hpp"
|
||||||
#include "Cubed/gameplay/cave_carver.hpp"
|
#include "Cubed/gameplay/cave_carver.hpp"
|
||||||
#include "Cubed/gameplay/chunk.hpp"
|
#include "Cubed/gameplay/chunk.hpp"
|
||||||
|
#include "Cubed/gameplay/game_time.hpp"
|
||||||
#include "Cubed/gameplay/river_worm.hpp"
|
#include "Cubed/gameplay/river_worm.hpp"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@@ -39,13 +40,21 @@ private:
|
|||||||
std::unordered_map<ChunkPos, const Chunk*, ChunkPos::Hash>;
|
std::unordered_map<ChunkPos, const Chunk*, ChunkPos::Hash>;
|
||||||
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
|
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
|
||||||
using ChunkHashMap = std::unordered_map<ChunkPos, Chunk, ChunkPos::Hash>;
|
using ChunkHashMap = std::unordered_map<ChunkPos, Chunk, ChunkPos::Hash>;
|
||||||
|
|
||||||
glm::vec3 m_gen_player_pos{0.0f, 0.0f, 0.0f};
|
glm::vec3 m_gen_player_pos{0.0f, 0.0f, 0.0f};
|
||||||
glm::vec3 m_sunlight_dir{1.0f, 2.0f, 1.0f};
|
|
||||||
ChunkHashMap m_chunks;
|
ChunkHashMap m_chunks;
|
||||||
std::unordered_map<std::size_t, Player> m_players;
|
std::unordered_map<std::size_t, Player> m_players;
|
||||||
std::vector<glm::vec4> m_planes;
|
std::vector<glm::vec4> m_planes;
|
||||||
|
|
||||||
std::thread m_gen_thread;
|
std::thread m_gen_thread;
|
||||||
|
std::thread m_server_thread;
|
||||||
|
|
||||||
|
std::stop_source m_server_stop_source;
|
||||||
|
|
||||||
|
std::atomic<int> m_per_tick_time = DEFAULT_PER_TICK_TIME; // ms
|
||||||
|
|
||||||
|
std::atomic<TickType> m_day_tick = 6000;
|
||||||
|
|
||||||
mutable std::mutex m_chunks_mutex;
|
mutable std::mutex m_chunks_mutex;
|
||||||
std::mutex m_gen_signal_mutex;
|
std::mutex m_gen_signal_mutex;
|
||||||
std::mutex m_new_chunk_queue_mutex;
|
std::mutex m_new_chunk_queue_mutex;
|
||||||
@@ -62,6 +71,9 @@ private:
|
|||||||
std::atomic<bool> m_could_gen{true};
|
std::atomic<bool> m_could_gen{true};
|
||||||
std::atomic<int> m_rendering_distance{24};
|
std::atomic<int> m_rendering_distance{24};
|
||||||
std::atomic<float> m_chunk_gen_fraction{0.0f};
|
std::atomic<float> m_chunk_gen_fraction{0.0f};
|
||||||
|
|
||||||
|
std::atomic<TickType> m_game_ticks{0};
|
||||||
|
|
||||||
std::vector<ChunkPos> m_dirty_queue;
|
std::vector<ChunkPos> m_dirty_queue;
|
||||||
std::vector<ChunkRenderSnapshot> m_render_snapshots;
|
std::vector<ChunkRenderSnapshot> m_render_snapshots;
|
||||||
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk;
|
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk;
|
||||||
@@ -120,7 +132,10 @@ public:
|
|||||||
int rendering_distance() const;
|
int rendering_distance() const;
|
||||||
void rendering_distance(int rendering_distance);
|
void rendering_distance(int rendering_distance);
|
||||||
void start_gen_thread();
|
void start_gen_thread();
|
||||||
|
void start_server_thread();
|
||||||
void stop_gen_thread();
|
void stop_gen_thread();
|
||||||
|
void stop_server_thread();
|
||||||
|
void serever_run(std::stop_token stoken);
|
||||||
|
|
||||||
CaveCarver& cave_carcer();
|
CaveCarver& cave_carcer();
|
||||||
RiverWorm& river_worm();
|
RiverWorm& river_worm();
|
||||||
@@ -128,6 +143,11 @@ public:
|
|||||||
std::vector<ChunkRenderSnapshot>& render_snapshots();
|
std::vector<ChunkRenderSnapshot>& render_snapshots();
|
||||||
|
|
||||||
glm::vec3 sunlight_dir() const;
|
glm::vec3 sunlight_dir() const;
|
||||||
|
TickType game_tick() const;
|
||||||
|
TickType day_tick() const;
|
||||||
|
void day_tick(TickType tick);
|
||||||
|
int per_tick_time() const;
|
||||||
|
void per_tick_time(int ms);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -31,6 +31,13 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr glm::vec3 SUNLIGHT_COLOR{1.0f, 1.0f, 1.0f};
|
static constexpr glm::vec3 SUNLIGHT_COLOR{1.0f, 1.0f, 1.0f};
|
||||||
|
static constexpr glm::vec3 SUN_COLOR{1.00f, 0.95f, 0.80f};
|
||||||
|
static constexpr glm::vec3 MOON_COLOR{0.75f, 0.80f, 1.00f};
|
||||||
|
static constexpr glm::vec3 SKY_COLOR{0.529, 0.808, 0.922};
|
||||||
|
static constexpr float FAR_PLANE = 1000.0f;
|
||||||
|
static constexpr float NEAR_PLANE = 0.1f;
|
||||||
|
static constexpr float SUN_SIZE = 50.0f;
|
||||||
|
static constexpr float MOON_SIZE = 50.0f;
|
||||||
const Camera& m_camera;
|
const Camera& m_camera;
|
||||||
DevPanel& m_dev_panel;
|
DevPanel& m_dev_panel;
|
||||||
const TextureManager& m_texture_manager;
|
const TextureManager& m_texture_manager;
|
||||||
@@ -75,6 +82,7 @@ private:
|
|||||||
2 - outline vao
|
2 - outline vao
|
||||||
3 - ui vao
|
3 - ui vao
|
||||||
4 - text vao
|
4 - text vao
|
||||||
|
|
||||||
*/
|
*/
|
||||||
std::vector<GLuint> m_vao;
|
std::vector<GLuint> m_vao;
|
||||||
std::vector<Vertex2D> m_ui;
|
std::vector<Vertex2D> m_ui;
|
||||||
|
|||||||
@@ -263,6 +263,29 @@ void DevPanel::show_biome_table_bar() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DevPanel::show_time_table_bar() {
|
||||||
|
World& world = m_app.world();
|
||||||
|
ImGui::Text("Game Tick %lld", world.game_tick());
|
||||||
|
ImGui::Text("Day Tick %lld", world.day_tick());
|
||||||
|
ImGui::Text("Set Day Tick");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::SliderInt("DayTick", &m_pre_set_day_tick, 0, DAY_TIME)) {
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Save##DayTick")) {
|
||||||
|
world.day_tick(static_cast<TickType>(m_pre_set_day_tick));
|
||||||
|
}
|
||||||
|
ImGui::Text("MSPT %d", world.per_tick_time());
|
||||||
|
ImGui::Text("Set MSPT");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::SliderInt("SetMSPT", &m_pre_set_tick_speed, 0, 200)) {
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Save##MSPT")) {
|
||||||
|
world.per_tick_time(m_pre_set_tick_speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DevPanel::show_cave_table_bar() {
|
void DevPanel::show_cave_table_bar() {
|
||||||
auto& cave_carcer = m_app.world().cave_carcer();
|
auto& cave_carcer = m_app.world().cave_carcer();
|
||||||
|
|
||||||
@@ -457,6 +480,10 @@ void DevPanel::show_world_tab_item() {
|
|||||||
ImGui::Text("Chunk Build Progress\n");
|
ImGui::Text("Chunk Build Progress\n");
|
||||||
ImGui::ProgressBar(m_app.world().chunk_gen_fraction());
|
ImGui::ProgressBar(m_app.world().chunk_gen_fraction());
|
||||||
if (ImGui::BeginTabBar("World Settings")) {
|
if (ImGui::BeginTabBar("World Settings")) {
|
||||||
|
if (ImGui::BeginTabItem("Time")) {
|
||||||
|
show_time_table_bar();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
if (ImGui::BeginTabItem("Cave")) {
|
if (ImGui::BeginTabItem("Cave")) {
|
||||||
show_cave_table_bar();
|
show_cave_table_bar();
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <execution>
|
#include <execution>
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
struct ChunkRenderData {
|
struct ChunkRenderData {
|
||||||
@@ -18,6 +20,7 @@ World::World() {}
|
|||||||
|
|
||||||
World::~World() {
|
World::~World() {
|
||||||
stop_gen_thread();
|
stop_gen_thread();
|
||||||
|
stop_server_thread();
|
||||||
m_chunks.clear();
|
m_chunks.clear();
|
||||||
{
|
{
|
||||||
std::lock_guard lk(m_delete_vbo_mutex);
|
std::lock_guard lk(m_delete_vbo_mutex);
|
||||||
@@ -86,6 +89,8 @@ void World::init_world() {
|
|||||||
auto d = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
|
auto d = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
|
||||||
Logger::info("Chunk Block Init Finish, Time Consuming: {}", d);
|
Logger::info("Chunk Block Init Finish, Time Consuming: {}", d);
|
||||||
|
|
||||||
|
start_server_thread();
|
||||||
|
|
||||||
Logger::info("TestPlayer Create Finish");
|
Logger::info("TestPlayer Create Finish");
|
||||||
}
|
}
|
||||||
void World::init_chunks() {
|
void World::init_chunks() {
|
||||||
@@ -727,6 +732,11 @@ void World::start_gen_thread() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::start_server_thread() {
|
||||||
|
m_server_thread = std::thread(
|
||||||
|
[this]() { serever_run(m_server_stop_source.get_token()); });
|
||||||
|
}
|
||||||
|
|
||||||
void World::stop_gen_thread() {
|
void World::stop_gen_thread() {
|
||||||
m_gen_running = false;
|
m_gen_running = false;
|
||||||
m_gen_cv.notify_all();
|
m_gen_cv.notify_all();
|
||||||
@@ -736,6 +746,23 @@ void World::stop_gen_thread() {
|
|||||||
Logger::info("Gen Thread Stopped");
|
Logger::info("Gen Thread Stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::stop_server_thread() {
|
||||||
|
m_server_stop_source.request_stop();
|
||||||
|
if (m_server_thread.joinable()) {
|
||||||
|
m_server_thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::serever_run(std::stop_token stoken) {
|
||||||
|
Logger::info("Server Thread Started!");
|
||||||
|
while (!stoken.stop_requested()) {
|
||||||
|
std::this_thread::sleep_for(milliseconds(m_per_tick_time));
|
||||||
|
++m_game_ticks;
|
||||||
|
m_day_tick = (++m_day_tick) % DAY_TIME;
|
||||||
|
}
|
||||||
|
Logger::info("Server Thread Stopped!");
|
||||||
|
}
|
||||||
|
|
||||||
void World::need_gen() {
|
void World::need_gen() {
|
||||||
if (!m_could_gen) {
|
if (!m_could_gen) {
|
||||||
Logger::warn("It is generating or consuming new chunks");
|
Logger::warn("It is generating or consuming new chunks");
|
||||||
@@ -1006,6 +1033,47 @@ std::vector<glm::vec4>& World::planes() { return m_planes; }
|
|||||||
std::vector<ChunkRenderSnapshot>& World::render_snapshots() {
|
std::vector<ChunkRenderSnapshot>& World::render_snapshots() {
|
||||||
return m_render_snapshots;
|
return m_render_snapshots;
|
||||||
};
|
};
|
||||||
glm::vec3 World::sunlight_dir() const { return m_sunlight_dir; }
|
/*
|
||||||
|
glm::vec3 World::sunlight_dir() const {
|
||||||
|
float t = static_cast<float>(m_day_tick) / DAY_TIME;
|
||||||
|
|
||||||
|
float azimuth = glm::radians(90.0f - t * 360.0f);
|
||||||
|
|
||||||
|
float altitude =
|
||||||
|
glm::half_pi<float>() * sin((t - 0.25f) * glm::two_pi<float>());
|
||||||
|
|
||||||
|
glm::vec3 dir{cos(altitude) * cos(azimuth), sin(altitude),
|
||||||
|
cos(altitude) * sin(azimuth)};
|
||||||
|
|
||||||
|
return glm::normalize(dir);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
glm::vec3 World::sunlight_dir() const {
|
||||||
|
float altitude = sin((m_day_tick - 6 * PER_HOUR) /
|
||||||
|
static_cast<float>(DAY_TIME / 2) * std::numbers::pi) *
|
||||||
|
90.0f;
|
||||||
|
|
||||||
|
float t = static_cast<float>(m_day_tick) / DAY_TIME;
|
||||||
|
float azimuth = 90.0f - 360.0f * (t - 0.25f);
|
||||||
|
|
||||||
|
float alt = glm::radians(altitude);
|
||||||
|
float az = glm::radians(azimuth);
|
||||||
|
glm::vec3 dir;
|
||||||
|
dir.x = cos(alt) * sin(az);
|
||||||
|
dir.y = sin(alt);
|
||||||
|
dir.z = cos(alt) * cos(az);
|
||||||
|
|
||||||
|
return glm::normalize(-dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
TickType World::game_tick() const { return m_game_ticks.load(); }
|
||||||
|
TickType World::day_tick() const { return m_day_tick.load(); }
|
||||||
|
void World::day_tick(TickType tick) {
|
||||||
|
tick %= DAY_TIME;
|
||||||
|
m_day_tick = tick;
|
||||||
|
}
|
||||||
|
int World::per_tick_time() const { return m_per_tick_time.load(); }
|
||||||
|
void World::per_tick_time(int ms) { m_per_tick_time = ms; }
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -257,13 +257,44 @@ void Renderer::render_sky() {
|
|||||||
|
|
||||||
glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_mv_mat));
|
glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_mv_mat));
|
||||||
glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_p_mat));
|
glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_p_mat));
|
||||||
|
glUniform3fv(shader.loc("color"), 1, glm::value_ptr(SKY_COLOR));
|
||||||
glBindVertexArray(m_vao[1]);
|
glBindVertexArray(m_vao[1]);
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
// draw sun and moon
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
glBindVertexArray(m_vao[0]);
|
||||||
|
// draw sum
|
||||||
|
glm::vec3 sun_pos = m_camera.get_camera_pos() +
|
||||||
|
normalize(-m_world.sunlight_dir()) * (FAR_PLANE * 0.9f);
|
||||||
|
glm::vec3 sun_view_pos = glm::vec3(m_v_mat * glm::vec4(sun_pos, 1.0f));
|
||||||
|
m_mv_mat = glm::translate(glm::mat4(1.0f), sun_view_pos) *
|
||||||
|
glm::scale(glm::mat4(1.0f), glm::vec3(SUN_SIZE)) *
|
||||||
|
glm::translate(glm::mat4(1.0f), glm::vec3(-0.5f, -0.5f, 0.0f));
|
||||||
|
glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_mv_mat));
|
||||||
|
glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_p_mat));
|
||||||
|
glUniform3fv(shader.loc("color"), 1, glm::value_ptr(SUN_COLOR));
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
glm::vec3 moon_pos = m_camera.get_camera_pos() +
|
||||||
|
normalize(m_world.sunlight_dir()) * (FAR_PLANE * 0.9f);
|
||||||
|
glm::vec3 moon_view_pos = glm::vec3(m_v_mat * glm::vec4(moon_pos, 1.0f));
|
||||||
|
m_mv_mat = glm::translate(glm::mat4(1.0f), moon_view_pos) *
|
||||||
|
glm::scale(glm::mat4(1.0f), glm::vec3(MOON_SIZE)) *
|
||||||
|
glm::translate(glm::mat4(1.0f), glm::vec3(-0.5f, -0.5f, 0.0f));
|
||||||
|
glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_mv_mat));
|
||||||
|
glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_p_mat));
|
||||||
|
glUniform3fv(shader.loc("color"), 1, glm::value_ptr(MOON_COLOR));
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::render_text() {
|
void Renderer::render_text() {
|
||||||
@@ -343,7 +374,8 @@ void Renderer::update_fov(float fov) {
|
|||||||
|
|
||||||
void Renderer::update_proj_matrix(float aspect, float width, float height) {
|
void Renderer::update_proj_matrix(float aspect, float width, float height) {
|
||||||
m_aspect = aspect;
|
m_aspect = aspect;
|
||||||
m_p_mat = glm::perspective(glm::radians(m_fov), aspect, 0.1f, 1000.0f);
|
m_p_mat =
|
||||||
|
glm::perspective(glm::radians(m_fov), aspect, NEAR_PLANE, FAR_PLANE);
|
||||||
m_ui_proj = glm::ortho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
|
m_ui_proj = glm::ortho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
|
||||||
// scale and then translate
|
// scale and then translate
|
||||||
m_ui_m_matrix =
|
m_ui_m_matrix =
|
||||||
|
|||||||
Reference in New Issue
Block a user