mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
refactor(game_time): introduce Timer for time-based updates and rename existing to TickTimer
Add a new `Timer` class that operates in seconds (using `TimeType`) alongside the existing `TickTimer` which uses `TickType`. Rename the original `Timer` to `TickTimer` throughout the codebase. Update `ClientWorld` to maintain separate maps for tick-based and time-based timers, and replace the hardcoded footstep timer in `ClientPlayer` with a time-based callback timer. Also add `play_2d` to `AudioEngine` and load an ambient bird sound to demonstrate the new timer functionality.
This commit is contained in:
BIN
assets/sound/ambient/birds.ogg
Normal file
BIN
assets/sound/ambient/birds.ogg
Normal file
Binary file not shown.
@@ -28,6 +28,7 @@ public:
|
|||||||
void play_bgm();
|
void play_bgm();
|
||||||
void play_3d(const std::string& sound, const glm::vec3& pos,
|
void play_3d(const std::string& sound, const glm::vec3& pos,
|
||||||
bool check = false);
|
bool check = false);
|
||||||
|
void play_2d(const std::string& sound, bool check = false);
|
||||||
void update_listener(const glm::vec3& pos, const glm::vec3& forward,
|
void update_listener(const glm::vec3& pos, const glm::vec3& forward,
|
||||||
const glm::vec3& up);
|
const glm::vec3& up);
|
||||||
void update();
|
void update();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "Cubed/gameplay/block.hpp"
|
#include "Cubed/gameplay/block.hpp"
|
||||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||||
#include "Cubed/gameplay/game_mode.hpp"
|
#include "Cubed/gameplay/game_mode.hpp"
|
||||||
|
#include "Cubed/gameplay/game_time.hpp"
|
||||||
#include "Cubed/gameplay/player.hpp"
|
#include "Cubed/gameplay/player.hpp"
|
||||||
#include "Cubed/input.hpp"
|
#include "Cubed/input.hpp"
|
||||||
|
|
||||||
@@ -123,7 +124,7 @@ private:
|
|||||||
float m_angle{0.0f};
|
float m_angle{0.0f};
|
||||||
float m_walk_time{0.0f};
|
float m_walk_time{0.0f};
|
||||||
|
|
||||||
float m_footstep_timer = 0.0f;
|
std::unordered_map<std::string, Timer> m_timers;
|
||||||
|
|
||||||
mutable std::shared_mutex m_player_pos_mutex;
|
mutable std::shared_mutex m_player_pos_mutex;
|
||||||
mutable std::shared_mutex m_chunk_pos_mutex;
|
mutable std::shared_mutex m_chunk_pos_mutex;
|
||||||
|
|||||||
@@ -92,10 +92,10 @@ public:
|
|||||||
static AABB get_block_aabb(const glm::ivec3& pos);
|
static AABB get_block_aabb(const glm::ivec3& pos);
|
||||||
AudioEngine& get_audio();
|
AudioEngine& get_audio();
|
||||||
template <typename Fn>
|
template <typename Fn>
|
||||||
void register_timer(std::string_view id, TickType threshold, Fn&& f) {
|
void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) {
|
||||||
m_timers.emplace(std::piecewise_construct,
|
m_ticktimers.emplace(
|
||||||
std::forward_as_tuple(std::string(id)),
|
std::piecewise_construct, std::forward_as_tuple(std::string(id)),
|
||||||
std::forward_as_tuple(threshold, std::forward<Fn>(f)));
|
std::forward_as_tuple(threshold, std::forward<Fn>(f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -136,7 +136,10 @@ private:
|
|||||||
std::deque<ChunkPos> m_dirty_queue;
|
std::deque<ChunkPos> m_dirty_queue;
|
||||||
std::vector<const ChunkRenderSnapshot*> m_render_snapshots;
|
std::vector<const ChunkRenderSnapshot*> m_render_snapshots;
|
||||||
std::vector<PlayerRenderData> m_render_player_data;
|
std::vector<PlayerRenderData> m_render_player_data;
|
||||||
tbb::concurrent_unordered_map<std::string, Timer> m_timers;
|
|
||||||
|
tbb::concurrent_unordered_map<std::string, TickTimer> m_ticktimers;
|
||||||
|
std::unordered_map<std::string, Timer> m_timers;
|
||||||
|
|
||||||
std::atomic<bool> m_game_running{false};
|
std::atomic<bool> m_game_running{false};
|
||||||
std::atomic<bool> m_receive_exit{false};
|
std::atomic<bool> m_receive_exit{false};
|
||||||
std::atomic<int> m_rendering_distance{24};
|
std::atomic<int> m_rendering_distance{24};
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
using TickType = long long;
|
using TickType = long long;
|
||||||
|
using TimeType = float;
|
||||||
|
|
||||||
constexpr int DEFAULT_PER_TICK_TIME = 50;
|
constexpr int DEFAULT_PER_TICK_TIME = 50;
|
||||||
|
|
||||||
@@ -14,10 +16,10 @@ constexpr TickType DAY_TIME = 24000;
|
|||||||
|
|
||||||
constexpr TickType PER_HOUR = 1000;
|
constexpr TickType PER_HOUR = 1000;
|
||||||
|
|
||||||
class Timer {
|
class TickTimer {
|
||||||
public:
|
public:
|
||||||
template <typename Fn>
|
template <typename Fn>
|
||||||
Timer(TickType threshold, Fn&& f)
|
TickTimer(TickType threshold, Fn&& f)
|
||||||
: m_fn(std::forward<Fn>(f)), m_threshold(threshold) {
|
: m_fn(std::forward<Fn>(f)), m_threshold(threshold) {
|
||||||
ASSERT_MSG(threshold > 0, "Threshold Must Rreater Than 0");
|
ASSERT_MSG(threshold > 0, "Threshold Must Rreater Than 0");
|
||||||
}
|
}
|
||||||
@@ -37,4 +39,37 @@ private:
|
|||||||
TickType m_current = 0;
|
TickType m_current = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Timer {
|
||||||
|
public:
|
||||||
|
template <typename Fn>
|
||||||
|
Timer(TimeType threshold, Fn&& f)
|
||||||
|
: m_fn(std::forward<Fn>(f)), m_threshold(threshold) {
|
||||||
|
ASSERT_MSG(threshold > 0, "Threshold Must Rreater Than 0");
|
||||||
|
}
|
||||||
|
bool update(TimeType dt) {
|
||||||
|
m_current += dt;
|
||||||
|
|
||||||
|
bool triggered = false;
|
||||||
|
|
||||||
|
while (m_current >= m_threshold) {
|
||||||
|
m_current -= m_threshold;
|
||||||
|
m_fn();
|
||||||
|
triggered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return triggered;
|
||||||
|
}
|
||||||
|
void reset() { m_current = 0.0f; }
|
||||||
|
void set_threshold(TimeType threshold) {
|
||||||
|
|
||||||
|
ASSERT_MSG(threshold > 0, "Threshold must be greater than 0");
|
||||||
|
m_threshold = threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void()> m_fn;
|
||||||
|
TimeType m_threshold;
|
||||||
|
TimeType m_current = 0;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ private:
|
|||||||
|
|
||||||
PlayerUUIDMap m_uuid_to_name;
|
PlayerUUIDMap m_uuid_to_name;
|
||||||
|
|
||||||
tbb::concurrent_unordered_map<std::string, Timer> m_timers;
|
tbb::concurrent_unordered_map<std::string, TickTimer> m_timers;
|
||||||
tbb::concurrent_queue<PendingRequest> m_waiting_chunk_requests;
|
tbb::concurrent_queue<PendingRequest> m_waiting_chunk_requests;
|
||||||
tbb::concurrent_queue<std::unique_ptr<ServerChunk>> m_finished_queue;
|
tbb::concurrent_queue<std::unique_ptr<ServerChunk>> m_finished_queue;
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,29 @@ void AudioEngine::play_3d(const std::string& sound, const glm::vec3& pos,
|
|||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
if (check) {
|
if (check) {
|
||||||
ASSERT_MSG(false, e.what());
|
ASSERT_MSG(false, e.what());
|
||||||
|
Logger::error("Player Sound Error {}", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioEngine::play_2d(const std::string& sound, bool check) {
|
||||||
|
if (!m_pool) {
|
||||||
|
Logger::error("Source Pool is nullptr");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto* source = m_pool->acquire();
|
||||||
|
source->set_volume(m_sfx_volume);
|
||||||
|
if (!source) {
|
||||||
|
Logger::error("Source is Full");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto& buffer = m_sounds.get_buffer(sound);
|
||||||
|
source->play_2d(buffer);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
if (check) {
|
||||||
|
ASSERT_MSG(false, e.what());
|
||||||
|
Logger::error("Player Sound Error {}", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ SoundManager::~SoundManager() { clear(); }
|
|||||||
void SoundManager::clear() { m_buffers.clear(); }
|
void SoundManager::clear() { m_buffers.clear(); }
|
||||||
void SoundManager::init() {
|
void SoundManager::init() {
|
||||||
try {
|
try {
|
||||||
// load("bgm/bgm001.mp3");
|
load("bgm/bgm001.mp3");
|
||||||
|
load("ambient/birds.ogg");
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,12 @@
|
|||||||
#include "Cubed/config.hpp"
|
#include "Cubed/config.hpp"
|
||||||
#include "Cubed/debug_collector.hpp"
|
#include "Cubed/debug_collector.hpp"
|
||||||
#include "Cubed/gameplay/client_world.hpp"
|
#include "Cubed/gameplay/client_world.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr float WALK_SOUND_INTERVAL = 0.45f;
|
||||||
|
constexpr float RUN_SOUND_INTERVAL = 0.3f;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
ClientPlayer::ClientPlayer(ClientWorld& world) : m_world(world) {}
|
ClientPlayer::ClientPlayer(ClientWorld& world) : m_world(world) {}
|
||||||
ClientPlayer::~ClientPlayer() {}
|
ClientPlayer::~ClientPlayer() {}
|
||||||
@@ -386,7 +392,19 @@ void ClientPlayer::update_move(float delta_time) {
|
|||||||
m_player_pos = player_pos;
|
m_player_pos = player_pos;
|
||||||
}
|
}
|
||||||
update_player_chunk();
|
update_player_chunk();
|
||||||
play_walk_sound(delta_time);
|
auto it = m_timers.find("Player Walk Sound");
|
||||||
|
|
||||||
|
if (it != m_timers.end()) {
|
||||||
|
if (m_sprinting) {
|
||||||
|
it->second.set_threshold(RUN_SOUND_INTERVAL);
|
||||||
|
} else {
|
||||||
|
it->second.set_threshold(WALK_SOUND_INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [key, timer] : m_timers) {
|
||||||
|
timer.update(delta_time);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientPlayer::update_x_move(glm::vec3& player_pos) {
|
void ClientPlayer::update_x_move(glm::vec3& player_pos) {
|
||||||
@@ -499,42 +517,6 @@ void ClientPlayer::update_player_chunk() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientPlayer::play_walk_sound(float dt) {
|
|
||||||
if (!m_moving || is_fly) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_footstep_timer += dt;
|
|
||||||
if (m_sprinting) {
|
|
||||||
const float WALK_INTERVAL = 0.3f;
|
|
||||||
|
|
||||||
if (m_footstep_timer < WALK_INTERVAL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const float WALK_INTERVAL = 0.45f;
|
|
||||||
|
|
||||||
if (m_footstep_timer < WALK_INTERVAL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_footstep_timer = 0.0f;
|
|
||||||
|
|
||||||
glm::ivec3 block = glm::floor(m_player_pos);
|
|
||||||
block.y -= 1;
|
|
||||||
BlockType id = m_world.get_block_tpye(block);
|
|
||||||
Logger::info("player Block {} Walk Sound", id);
|
|
||||||
if (id == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::string name = BlockManager::name_form_id(id);
|
|
||||||
std::string sound = "block/" + name + "/walk.ogg";
|
|
||||||
auto& audio = m_world.get_audio();
|
|
||||||
audio.play_3d(sound, m_player_pos);
|
|
||||||
Logger::info("Player block {} walk sound", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Gait ClientPlayer::compute_gait() const {
|
Gait ClientPlayer::compute_gait() const {
|
||||||
if (m_xz_speed < 0.01f)
|
if (m_xz_speed < 0.01f)
|
||||||
return Gait::STOP;
|
return Gait::STOP;
|
||||||
@@ -610,7 +592,28 @@ std::string ClientPlayer::get_uuid() const {
|
|||||||
return m_uuid;
|
return m_uuid;
|
||||||
}
|
}
|
||||||
const std::string& ClientPlayer::get_name() const { return m_name; }
|
const std::string& ClientPlayer::get_name() const { return m_name; }
|
||||||
void ClientPlayer::init(std::string_view name) { m_name = name; }
|
void ClientPlayer::init(std::string_view name) {
|
||||||
|
|
||||||
|
m_name = name;
|
||||||
|
|
||||||
|
m_timers.try_emplace("Player Walk Sound", WALK_SOUND_INTERVAL, [this]() {
|
||||||
|
if (!m_moving || is_fly) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
glm::ivec3 block = glm::floor(m_player_pos);
|
||||||
|
block.y -= 1;
|
||||||
|
BlockType id = m_world.get_block_tpye(block);
|
||||||
|
Logger::info("player Block {} Walk Sound", id);
|
||||||
|
if (id == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::string name = BlockManager::name_form_id(id);
|
||||||
|
std::string sound = "block/" + name + "/walk.ogg";
|
||||||
|
auto& audio = m_world.get_audio();
|
||||||
|
audio.play_3d(sound, m_player_pos);
|
||||||
|
Logger::info("Player block {} walk sound", name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
float ClientPlayer::yaw() const { return m_yaw; }
|
float ClientPlayer::yaw() const { return m_yaw; }
|
||||||
float ClientPlayer::pitch() const { return m_pitch; }
|
float ClientPlayer::pitch() const { return m_pitch; }
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ ClientWorld::~ClientWorld() {
|
|||||||
}
|
}
|
||||||
m_pending_delete_vao.clear();
|
m_pending_delete_vao.clear();
|
||||||
}
|
}
|
||||||
m_timers.clear();
|
m_ticktimers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::optional<LookBlock>& ClientWorld::get_look_block_pos() const {
|
const std::optional<LookBlock>& ClientWorld::get_look_block_pos() const {
|
||||||
@@ -358,7 +358,23 @@ void ClientWorld::init(std::string_view player_name,
|
|||||||
m_player.init(player_name);
|
m_player.init(player_name);
|
||||||
m_client = client;
|
m_client = client;
|
||||||
// timer
|
// timer
|
||||||
register_timer("player_pos", 1, [this]() { report_player_info(); });
|
register_ticktimer("player_pos", 1, [this]() { report_player_info(); });
|
||||||
|
m_timers.try_emplace("Birds Sound", 60.0f, [this]() {
|
||||||
|
auto player_pos = m_player.get_player_pos();
|
||||||
|
if (player_pos.y < SEA_LEVEL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ChunkPos pos = get_chunk_pos(player_pos.x, player_pos.z);
|
||||||
|
{
|
||||||
|
chunk_cacc cacc;
|
||||||
|
if (m_chunks.find(cacc, pos)) {
|
||||||
|
if (cacc->second->get_biome() == BiomeType::FOREST) {
|
||||||
|
m_audio.play_2d("ambient/birds.ogg", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
LoginReq req;
|
LoginReq req;
|
||||||
req.set_name(m_player.get_name());
|
req.set_name(m_player.get_name());
|
||||||
while (!client->is_connected()) {
|
while (!client->is_connected()) {
|
||||||
@@ -443,7 +459,7 @@ void ClientWorld::client_run(std::stop_token stoken) {
|
|||||||
auto next = Clock::now();
|
auto next = Clock::now();
|
||||||
while (!stoken.stop_requested()) {
|
while (!stoken.stop_requested()) {
|
||||||
next += TICK;
|
next += TICK;
|
||||||
for (auto& x : m_timers) {
|
for (auto& x : m_ticktimers) {
|
||||||
x.second.update();
|
x.second.update();
|
||||||
}
|
}
|
||||||
std::this_thread::sleep_until(next);
|
std::this_thread::sleep_until(next);
|
||||||
@@ -779,6 +795,10 @@ void ClientWorld::update(float delta_time) {
|
|||||||
while (m_pending_sound.try_pop(pending_sound)) {
|
while (m_pending_sound.try_pop(pending_sound)) {
|
||||||
m_audio.play_3d(pending_sound.sound, pending_sound.sound_pos);
|
m_audio.play_3d(pending_sound.sound, pending_sound.sound_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& [pos, timer] : m_timers) {
|
||||||
|
timer.update(delta_time);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 ClientWorld::sunlight_dir() const {
|
glm::vec3 ClientWorld::sunlight_dir() const {
|
||||||
|
|||||||
Reference in New Issue
Block a user