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_3d(const std::string& sound, const glm::vec3& pos,
|
||||
bool check = false);
|
||||
void play_2d(const std::string& sound, bool check = false);
|
||||
void update_listener(const glm::vec3& pos, const glm::vec3& forward,
|
||||
const glm::vec3& up);
|
||||
void update();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Cubed/gameplay/block.hpp"
|
||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||
#include "Cubed/gameplay/game_mode.hpp"
|
||||
#include "Cubed/gameplay/game_time.hpp"
|
||||
#include "Cubed/gameplay/player.hpp"
|
||||
#include "Cubed/input.hpp"
|
||||
|
||||
@@ -123,7 +124,7 @@ private:
|
||||
float m_angle{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_chunk_pos_mutex;
|
||||
|
||||
@@ -92,10 +92,10 @@ public:
|
||||
static AABB get_block_aabb(const glm::ivec3& pos);
|
||||
AudioEngine& get_audio();
|
||||
template <typename Fn>
|
||||
void register_timer(std::string_view id, TickType threshold, Fn&& f) {
|
||||
m_timers.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(std::string(id)),
|
||||
std::forward_as_tuple(threshold, std::forward<Fn>(f)));
|
||||
void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) {
|
||||
m_ticktimers.emplace(
|
||||
std::piecewise_construct, std::forward_as_tuple(std::string(id)),
|
||||
std::forward_as_tuple(threshold, std::forward<Fn>(f)));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -136,7 +136,10 @@ private:
|
||||
std::deque<ChunkPos> m_dirty_queue;
|
||||
std::vector<const ChunkRenderSnapshot*> m_render_snapshots;
|
||||
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_receive_exit{false};
|
||||
std::atomic<int> m_rendering_distance{24};
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
namespace Cubed {
|
||||
|
||||
using TickType = long long;
|
||||
using TimeType = float;
|
||||
|
||||
constexpr int DEFAULT_PER_TICK_TIME = 50;
|
||||
|
||||
@@ -14,10 +16,10 @@ constexpr TickType DAY_TIME = 24000;
|
||||
|
||||
constexpr TickType PER_HOUR = 1000;
|
||||
|
||||
class Timer {
|
||||
class TickTimer {
|
||||
public:
|
||||
template <typename Fn>
|
||||
Timer(TickType threshold, Fn&& f)
|
||||
TickTimer(TickType threshold, Fn&& f)
|
||||
: m_fn(std::forward<Fn>(f)), m_threshold(threshold) {
|
||||
ASSERT_MSG(threshold > 0, "Threshold Must Rreater Than 0");
|
||||
}
|
||||
@@ -37,4 +39,37 @@ private:
|
||||
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
|
||||
|
||||
@@ -156,7 +156,7 @@ private:
|
||||
|
||||
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<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) {
|
||||
if (check) {
|
||||
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::init() {
|
||||
try {
|
||||
// load("bgm/bgm001.mp3");
|
||||
load("bgm/bgm001.mp3");
|
||||
load("ambient/birds.ogg");
|
||||
} catch (const std::exception& e) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
#include "Cubed/config.hpp"
|
||||
#include "Cubed/debug_collector.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 {
|
||||
ClientPlayer::ClientPlayer(ClientWorld& world) : m_world(world) {}
|
||||
ClientPlayer::~ClientPlayer() {}
|
||||
@@ -386,7 +392,19 @@ void ClientPlayer::update_move(float delta_time) {
|
||||
m_player_pos = player_pos;
|
||||
}
|
||||
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) {
|
||||
@@ -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 {
|
||||
if (m_xz_speed < 0.01f)
|
||||
return Gait::STOP;
|
||||
@@ -610,7 +592,28 @@ std::string ClientPlayer::get_uuid() const {
|
||||
return m_uuid;
|
||||
}
|
||||
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::pitch() const { return m_pitch; }
|
||||
|
||||
@@ -43,7 +43,7 @@ ClientWorld::~ClientWorld() {
|
||||
}
|
||||
m_pending_delete_vao.clear();
|
||||
}
|
||||
m_timers.clear();
|
||||
m_ticktimers.clear();
|
||||
}
|
||||
|
||||
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_client = client;
|
||||
// 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;
|
||||
req.set_name(m_player.get_name());
|
||||
while (!client->is_connected()) {
|
||||
@@ -443,7 +459,7 @@ void ClientWorld::client_run(std::stop_token stoken) {
|
||||
auto next = Clock::now();
|
||||
while (!stoken.stop_requested()) {
|
||||
next += TICK;
|
||||
for (auto& x : m_timers) {
|
||||
for (auto& x : m_ticktimers) {
|
||||
x.second.update();
|
||||
}
|
||||
std::this_thread::sleep_until(next);
|
||||
@@ -779,6 +795,10 @@ void ClientWorld::update(float delta_time) {
|
||||
while (m_pending_sound.try_pop(pending_sound)) {
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user