mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
feat: sound (#28)
* build: add OpenAL dependency * feat(deps): add dr_libs audio library * feat(audio): integrate OpenAL audio engine with WAV/MP3/FLAC support * feat: add bgm001 * feat(audio): add audio fade in/out and fix delta time naming * fix(audio-source): improve state, volume, and const correctness * feat(audio): add 3D audio playback with source pool and auto-loading * feat: add ogg loader * feat(audio): add footstep sounds and fix audio listener orientation * feat(sound): add block place and break sounds * feat(audio): add per-channel volume control and config reload * fix(audio): set distance model, reduce max distance, fix sound pos - Set OpenAL distance model to AL_INVERSE_DISTANCE_CLAMPED in engine. - Reduced AL_MAX_DISTANCE from 100 to 48 for better falloff. - Fixed block sound position to use world coordinates instead of local block coordinates. * 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. * feat(gameplay): add ocean wave ambient sounds with random selection Add four ocean wave FLAC sound files and play one randomly when player is within 10 blocks of sea level and in an ocean biome. Include a Random member initialized from ChunkGenerator seed for consistent randomization. * feat(gameplay): detect underwater state and play transition/bubble sounds - Add is_underwater() and set_underwater() to ClientPlayer. - Change get_world() to return non-const reference for audio access. - Update Camera::update_move_camera() to detect water block changes and trigger transition sound. - Add repeating timer in ClientWorld to play random bubble ambient sounds while underwater. - Include new ambient sound assets for water transitions and bubbles. - Also add sand walk sound asset (unused in this commit). * feat(assets): add and update block break/place/walk sounds Add sounds for dirt, grass_block, leaf, log, sand, snowy_grass_block, stone. Update existing leaf/walk, sand/place, sand/walk, and stone/place sounds. * feat(gameplay): add walking sound for players and adjust underwater bubble interval - Move walk/run sound interval constants from anonymous namespace to ClientPlayer header - Add moving_time field to PlayerInfo to track continuous movement - Implement play_walk_sound callback triggered by WALK and RUN gaits - Increase underwater bubble timer from 1.0s to 1.5s * feat(asset): add grass block break and place sound effects * feat(renderer): add --no-debug flag to disable OpenGL debug output * feat(audio): add day/night-based BGM switching * feat(audio): add underwater low-pass filter effect * feat(audio): add pitch control to audio sources Implement set_pitch method that clamps pitch between 0.0 and 1.0 and applies it via AL_PITCH. Includes minor whitespace cleanup in audio_engine.cpp. * feat(audio): implement reverb effect and integrate into underwater system * asset(sound): update dirt and grass block break/place sounds * feat(network): synchronize player water sound * fix: include <numbers> * fix(audio): play ambient water bubble sound in 3D at player position
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "Cubed/audio/audio_engine.hpp"
|
||||
#include "Cubed/gameplay/client_world.hpp"
|
||||
#include "Cubed/gameplay/network_server.hpp"
|
||||
#include "Cubed/gameplay/server_world.hpp"
|
||||
@@ -17,6 +18,7 @@ public:
|
||||
int port = 25530;
|
||||
std::string ip{"127.0.0.1"};
|
||||
std::string player{"Unknown"};
|
||||
bool debug_on = true;
|
||||
};
|
||||
|
||||
App();
|
||||
@@ -37,7 +39,7 @@ public:
|
||||
static int start_cubed_application(int argc, char** argv);
|
||||
|
||||
static unsigned int seed();
|
||||
static float delte_time();
|
||||
static float delta_time();
|
||||
static float get_fps();
|
||||
|
||||
Camera& camera();
|
||||
@@ -48,6 +50,7 @@ public:
|
||||
ClientWorld& client_world();
|
||||
ServerWorld& server_world();
|
||||
const Argument& argument() const;
|
||||
AudioEngine& audio();
|
||||
|
||||
private:
|
||||
Camera m_camera;
|
||||
@@ -62,9 +65,11 @@ private:
|
||||
|
||||
Window m_window{m_renderer};
|
||||
|
||||
AudioEngine m_audio;
|
||||
|
||||
inline static double last_time = glfwGetTime();
|
||||
inline static double current_time = glfwGetTime();
|
||||
inline static double delta_time = 0.0f;
|
||||
inline static double dt = 0.0f;
|
||||
inline static double fps_time_count = 0.0f;
|
||||
inline static int frame_count = 0;
|
||||
inline static int fps = 0;
|
||||
|
||||
24
include/Cubed/audio/audio_buffer.hpp
Normal file
24
include/Cubed/audio/audio_buffer.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "Cubed/audio/audio_data.hpp"
|
||||
|
||||
#include <AL/al.h>
|
||||
namespace Cubed {
|
||||
class AudioBuffer {
|
||||
public:
|
||||
AudioBuffer(const AudioData& data);
|
||||
AudioBuffer(const AudioBuffer&) = delete;
|
||||
AudioBuffer(AudioBuffer&&) = delete;
|
||||
AudioBuffer& operator=(const AudioBuffer&) = delete;
|
||||
AudioBuffer& operator=(AudioBuffer&&) = delete;
|
||||
~AudioBuffer();
|
||||
ALuint buffer() const;
|
||||
float duration() const;
|
||||
uint32_t channels() const;
|
||||
|
||||
private:
|
||||
ALuint m_buffer = 0;
|
||||
float m_duration = 0.0f;
|
||||
uint32_t m_channels = 0;
|
||||
void set_data(const AudioData& data);
|
||||
};
|
||||
} // namespace Cubed
|
||||
10
include/Cubed/audio/audio_data.hpp
Normal file
10
include/Cubed/audio/audio_data.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
namespace Cubed {
|
||||
struct AudioData {
|
||||
std::vector<int16_t> pcm;
|
||||
uint32_t channels;
|
||||
uint32_t sample_rate;
|
||||
};
|
||||
} // namespace Cubed
|
||||
19
include/Cubed/audio/audio_effect.hpp
Normal file
19
include/Cubed/audio/audio_effect.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <AL/al.h>
|
||||
namespace Cubed {
|
||||
class AudioEffect {
|
||||
public:
|
||||
AudioEffect();
|
||||
AudioEffect(const AudioEffect&) = delete;
|
||||
AudioEffect(AudioEffect&&) = delete;
|
||||
AudioEffect& operator=(const AudioEffect&) = default;
|
||||
AudioEffect& operator=(AudioEffect&&) = delete;
|
||||
~AudioEffect();
|
||||
void set_reverb(float decay_time, float reverb_gain, float gain_hf,
|
||||
float density = 1.0f, float diffusion = 1.0f);
|
||||
ALuint effect() const;
|
||||
|
||||
private:
|
||||
ALuint m_effect = 0;
|
||||
};
|
||||
} // namespace Cubed
|
||||
18
include/Cubed/audio/audio_effect_slot.hpp
Normal file
18
include/Cubed/audio/audio_effect_slot.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include "Cubed/audio/audio_effect.hpp"
|
||||
namespace Cubed {
|
||||
class AudioEffectSlot {
|
||||
public:
|
||||
AudioEffectSlot();
|
||||
AudioEffectSlot(const AudioEffectSlot&) = delete;
|
||||
AudioEffectSlot(AudioEffectSlot&&) = delete;
|
||||
AudioEffectSlot& operator=(const AudioEffectSlot&) = delete;
|
||||
AudioEffectSlot& operator=(AudioEffectSlot&&) = delete;
|
||||
~AudioEffectSlot();
|
||||
void set_effect(const AudioEffect& effect);
|
||||
ALuint slot() const;
|
||||
|
||||
private:
|
||||
ALuint m_slot = 0;
|
||||
};
|
||||
} // namespace Cubed
|
||||
60
include/Cubed/audio/audio_engine.hpp
Normal file
60
include/Cubed/audio/audio_engine.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cubed/audio/audio_fade.hpp"
|
||||
#include "Cubed/audio/audio_source.hpp"
|
||||
#include "Cubed/audio/sound_manager.hpp"
|
||||
#include "Cubed/audio/source_pool.hpp"
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
namespace Cubed {
|
||||
|
||||
class ClientWorld;
|
||||
|
||||
class AudioEngine {
|
||||
public:
|
||||
AudioEngine();
|
||||
AudioEngine(const AudioEngine&) = delete;
|
||||
AudioEngine(AudioEngine&&) = delete;
|
||||
AudioEngine& operator=(const AudioEngine&) = delete;
|
||||
AudioEngine& operator=(AudioEngine&&) = delete;
|
||||
~AudioEngine();
|
||||
|
||||
void init();
|
||||
void play_bgm();
|
||||
void change_bgm(const std::string& sound);
|
||||
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();
|
||||
void reload_config();
|
||||
|
||||
void underwater_change(bool underwater);
|
||||
|
||||
float& bgm_target_volume();
|
||||
|
||||
private:
|
||||
using FadeMap = std::unordered_map<std::string, AudioFade>;
|
||||
bool m_init{false};
|
||||
ALCdevice* device{nullptr};
|
||||
ALCcontext* context{nullptr};
|
||||
glm::vec3 listener_pos;
|
||||
std::unique_ptr<AudioSource> m_bgm;
|
||||
FadeMap m_fade_map;
|
||||
SoundManager m_sounds;
|
||||
std::shared_ptr<SourcePool> m_pool;
|
||||
bool m_efx_supported = false;
|
||||
bool m_underwater = false;
|
||||
float m_music_volume = 1.0f;
|
||||
float m_sfx_volume = 1.0f;
|
||||
std::unique_ptr<AudioFilter> m_low_pass_filter;
|
||||
std::unique_ptr<AudioEffect> m_underwater_effect;
|
||||
std::unique_ptr<AudioEffectSlot> m_underwater_slot;
|
||||
};
|
||||
} // namespace Cubed
|
||||
15
include/Cubed/audio/audio_error.hpp
Normal file
15
include/Cubed/audio/audio_error.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "Cubed/tools/log.hpp"
|
||||
|
||||
#include <AL/al.h>
|
||||
namespace Cubed {
|
||||
inline void check_al_error(
|
||||
std::source_location loaction = std::source_location::current()) {
|
||||
ALenum error = alGetError();
|
||||
if (error != AL_NO_ERROR) {
|
||||
Logger::error("File {} Line {} Function {} OpenAL Error {} ",
|
||||
loaction.file_name(), loaction.line(),
|
||||
loaction.function_name(), alGetString(error));
|
||||
}
|
||||
}
|
||||
} // namespace Cubed
|
||||
19
include/Cubed/audio/audio_fade.hpp
Normal file
19
include/Cubed/audio/audio_fade.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "Cubed/audio/audio_source.hpp"
|
||||
namespace Cubed {
|
||||
class AudioFade {
|
||||
public:
|
||||
AudioFade(AudioSource* source, float fade_in = 0.0f, float fade_out = 0.0f);
|
||||
~AudioFade();
|
||||
void update();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
AudioSource* m_source = nullptr;
|
||||
float m_in_duration = 0.0f;
|
||||
float m_out_duration = 0.0f;
|
||||
float m_start_gain = 0.0f;
|
||||
bool m_fade_in = true;
|
||||
bool m_active = true;
|
||||
};
|
||||
} // namespace Cubed
|
||||
19
include/Cubed/audio/audio_filter.hpp
Normal file
19
include/Cubed/audio/audio_filter.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <AL/al.h>
|
||||
namespace Cubed {
|
||||
class AudioFilter {
|
||||
public:
|
||||
AudioFilter();
|
||||
AudioFilter(const AudioFilter&) = delete;
|
||||
AudioFilter(AudioFilter&&) = delete;
|
||||
AudioFilter& operator=(const AudioFilter&) = delete;
|
||||
AudioFilter& operator=(AudioFilter&&) = delete;
|
||||
~AudioFilter();
|
||||
|
||||
void set_lowpass(float gain, float gain_hf);
|
||||
ALuint filter() const;
|
||||
|
||||
private:
|
||||
ALuint m_filter = 0;
|
||||
};
|
||||
} // namespace Cubed
|
||||
17
include/Cubed/audio/audio_loader.hpp
Normal file
17
include/Cubed/audio/audio_loader.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "Cubed/audio/audio_data.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
namespace Cubed {
|
||||
|
||||
class AudioLoader {
|
||||
public:
|
||||
static AudioData load(const std::filesystem::path& path);
|
||||
|
||||
private:
|
||||
static AudioData load_wav(const std::filesystem::path& path);
|
||||
static AudioData load_mp3(const std::filesystem::path& path);
|
||||
static AudioData load_flac(const std::filesystem::path& path);
|
||||
static AudioData load_ogg(const std::filesystem::path& path);
|
||||
};
|
||||
} // namespace Cubed
|
||||
50
include/Cubed/audio/audio_source.hpp
Normal file
50
include/Cubed/audio/audio_source.hpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
#include "Cubed/audio/audio_buffer.hpp"
|
||||
#include "Cubed/audio/audio_effect_slot.hpp"
|
||||
#include "Cubed/audio/audio_filter.hpp"
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <glm/glm.hpp>
|
||||
namespace Cubed {
|
||||
|
||||
enum class AudioState { INITIAL, PLAYING, PAUSED, STOPPED };
|
||||
|
||||
class AudioSource {
|
||||
public:
|
||||
AudioSource(float volume = 1.0f);
|
||||
~AudioSource();
|
||||
|
||||
void set_buffer_2d(const AudioBuffer& buffer);
|
||||
void set_buffer_3d(const AudioBuffer& buffer, const glm::vec3& vec3);
|
||||
void set_loop(bool on = true);
|
||||
void set_volume(float volume);
|
||||
void set_pitch(float pitch);
|
||||
void play();
|
||||
void play_2d(const AudioBuffer& buffer);
|
||||
void play_3d(const AudioBuffer& buffer, const glm::vec3& pos);
|
||||
|
||||
void stop();
|
||||
void pause();
|
||||
float duration() const;
|
||||
float current_time() const;
|
||||
float target_volume() const;
|
||||
float& target_volume();
|
||||
void set_target_volume(float volume);
|
||||
AudioState state() const;
|
||||
|
||||
void mark_in_use();
|
||||
bool in_use() const;
|
||||
void reset();
|
||||
|
||||
void set_filter(const AudioFilter& filter);
|
||||
void clear_filter();
|
||||
void set_effect_slot(const AudioEffectSlot& slot);
|
||||
void clear_effect_slot();
|
||||
|
||||
private:
|
||||
ALuint m_source = 0;
|
||||
float m_target_volume = 1.0f;
|
||||
float m_duration = 0.0f;
|
||||
bool m_using;
|
||||
};
|
||||
} // namespace Cubed
|
||||
19
include/Cubed/audio/sound_manager.hpp
Normal file
19
include/Cubed/audio/sound_manager.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "Cubed/audio/audio_buffer.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
namespace Cubed {
|
||||
class SoundManager {
|
||||
public:
|
||||
SoundManager();
|
||||
~SoundManager();
|
||||
const AudioBuffer& load(const std::string& name);
|
||||
const AudioBuffer& get_buffer(const std::string& name);
|
||||
void init();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, AudioBuffer> m_buffers;
|
||||
};
|
||||
} // namespace Cubed
|
||||
23
include/Cubed/audio/source_pool.hpp
Normal file
23
include/Cubed/audio/source_pool.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "Cubed/audio/audio_source.hpp"
|
||||
|
||||
namespace Cubed {
|
||||
class SourcePool {
|
||||
private:
|
||||
std::vector<AudioSource> m_sources;
|
||||
|
||||
public:
|
||||
explicit SourcePool(size_t size);
|
||||
~SourcePool();
|
||||
SourcePool(const SourcePool&) = delete;
|
||||
SourcePool(SourcePool&&) = delete;
|
||||
SourcePool& operator=(const SourcePool&) = delete;
|
||||
SourcePool& operator=(SourcePool&&) = delete;
|
||||
|
||||
void update();
|
||||
AudioSource* acquire();
|
||||
|
||||
std::vector<AudioSource>& sources();
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -20,6 +20,8 @@ class DevPanel {
|
||||
bool is_enable_aniso = false;
|
||||
bool is_support_aniso = true;
|
||||
bool is_reload = true;
|
||||
float volume_music = 1.0f;
|
||||
float volume_sfx = 1.0f;
|
||||
};
|
||||
struct PlayerProfile {
|
||||
int game_mode = 0;
|
||||
|
||||
@@ -76,6 +76,7 @@ public:
|
||||
void need_upload();
|
||||
|
||||
void set_chunk_block(int index, unsigned id);
|
||||
BlockType get_chunk_block(int index);
|
||||
bool is_temp_chunk() const;
|
||||
ChunkPos chunk_pos() const;
|
||||
BiomeType biome() const;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -16,6 +17,8 @@ namespace Cubed {
|
||||
class ClientWorld;
|
||||
class ClientPlayer {
|
||||
public:
|
||||
static constexpr float WALK_SOUND_INTERVAL = 0.45f;
|
||||
static constexpr float RUN_SOUND_INTERVAL = 0.3f;
|
||||
using ChunkPosSet = absl::flat_hash_set<ChunkPos, ChunkPos::Hash>;
|
||||
ClientPlayer(ClientWorld& world);
|
||||
~ClientPlayer();
|
||||
@@ -54,7 +57,7 @@ public:
|
||||
void set_gait(Gait gait);
|
||||
GameMode& game_mode();
|
||||
|
||||
const ClientWorld& get_world() const;
|
||||
ClientWorld& get_world();
|
||||
|
||||
void set_uuid(std::string_view uuid);
|
||||
std::string get_uuid() const;
|
||||
@@ -69,6 +72,8 @@ public:
|
||||
bool ray_cast(const glm::vec3& start, const glm::vec3& dir,
|
||||
glm::ivec3& block_pos, glm::vec3& normal,
|
||||
float distance = 4.0f);
|
||||
bool is_underwater() const;
|
||||
void set_underwater(bool u);
|
||||
|
||||
private:
|
||||
using enum GameMode;
|
||||
@@ -99,6 +104,7 @@ private:
|
||||
|
||||
bool m_moving = false;
|
||||
bool m_sprinting = false;
|
||||
bool m_underwater = false;
|
||||
|
||||
glm::vec3 direction = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
glm::vec3 move_distance{0.0f, 0.0f, 0.0f};
|
||||
@@ -123,6 +129,8 @@ private:
|
||||
float m_angle{0.0f};
|
||||
float m_walk_time{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;
|
||||
ChunkPosSet m_player_chunk_pos_set;
|
||||
@@ -134,6 +142,7 @@ private:
|
||||
void update_y_move(glm::vec3& player_pos);
|
||||
void update_z_move(glm::vec3& player_pos);
|
||||
void update_player_chunk();
|
||||
void play_walk_sound(float dt);
|
||||
Gait compute_gait() const;
|
||||
};
|
||||
} // namespace Cubed
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
#include "Cubed/audio/audio_engine.hpp"
|
||||
#include "Cubed/gameplay/block.hpp"
|
||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||
#include "Cubed/gameplay/client_chunk.hpp"
|
||||
#include "Cubed/gameplay/client_player.hpp"
|
||||
#include "Cubed/gameplay/game_time.hpp"
|
||||
#include "Cubed/gameplay/network_client.hpp"
|
||||
#include "Cubed/tools/cubed_random.hpp"
|
||||
#include "Cubed/tools/priority_thread_pool.hpp"
|
||||
|
||||
#include <absl/container/flat_hash_set.h>
|
||||
@@ -26,6 +28,7 @@ struct PlayerInfo {
|
||||
Gait gait;
|
||||
float angle = 0.0f;
|
||||
float walk_time = 0.0f;
|
||||
float moving_time = 0.0f;
|
||||
};
|
||||
|
||||
struct PlayerRenderData {
|
||||
@@ -40,7 +43,7 @@ struct PlayerRenderData {
|
||||
|
||||
class ClientWorld {
|
||||
public:
|
||||
ClientWorld();
|
||||
ClientWorld(AudioEngine& auido);
|
||||
~ClientWorld();
|
||||
void init(std::string_view player_name,
|
||||
std::shared_ptr<NetworkClient> client);
|
||||
@@ -66,6 +69,8 @@ public:
|
||||
|
||||
void receive_remote_player(const PlayerInfoRsp& rsp);
|
||||
void receive_player_logout(const LogoutRsp& rsp);
|
||||
void receive_player_water_sound(const PlayerWaterSound& rsp);
|
||||
void send_player_water_sound(bool underwater, const glm::vec3& pos);
|
||||
int rendering_distance() const;
|
||||
void rendering_distance(int rendering_distance);
|
||||
int get_chunk_task_id() const;
|
||||
@@ -89,12 +94,12 @@ public:
|
||||
bool is_receive_exit();
|
||||
int chunk_size() const;
|
||||
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:
|
||||
@@ -107,11 +112,18 @@ private:
|
||||
using OtherPlayerHashMap = std::unordered_map<std::string, PlayerInfo>;
|
||||
using chunk_acc = ChunkHashMap::accessor;
|
||||
using chunk_cacc = ChunkHashMap::const_accessor;
|
||||
|
||||
struct PendingSound {
|
||||
std::string sound;
|
||||
glm::vec3 sound_pos;
|
||||
};
|
||||
|
||||
static constexpr int WORLD_EXIT_TIMEOUT = 200;
|
||||
static constexpr int MAX_UPLOAD_CHUNK_SUM = 16;
|
||||
ClientPlayer m_player;
|
||||
OtherPlayerHashMap m_player_info;
|
||||
ChunkHashMap m_chunks;
|
||||
AudioEngine& m_audio;
|
||||
std::vector<glm::vec4> m_planes;
|
||||
std::jthread m_client_thread;
|
||||
|
||||
@@ -121,14 +133,17 @@ private:
|
||||
|
||||
tbb::concurrent_queue<std::unique_ptr<ClientChunk>> m_pending_upload_queue;
|
||||
tbb::concurrent_queue<ChunkPos> m_dirty_chunk_queue;
|
||||
|
||||
tbb::concurrent_queue<PendingSound> m_pending_sound;
|
||||
std::vector<GLuint> m_pending_delete_vbo;
|
||||
std::vector<GLuint> m_pending_delete_vao;
|
||||
|
||||
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};
|
||||
@@ -142,6 +157,8 @@ private:
|
||||
|
||||
std::atomic<std::shared_ptr<PriorityThreadPool>> m_thread_pool;
|
||||
|
||||
Random m_random;
|
||||
|
||||
void client_run(std::stop_token token);
|
||||
|
||||
void report_player_info();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -54,6 +54,7 @@ enum class PacketEnum : uint16_t {
|
||||
PLAYER_INFO = 2001,
|
||||
C2S_PLAYER_INFO = 2002,
|
||||
PLAYER_INFO_RSP = 2003,
|
||||
PLAYER_WATER_SOUND = 2004,
|
||||
CHUNK_DATA_REQ = 3001,
|
||||
CHUNK_DATA_RSP = 3002,
|
||||
BLOCK_CHANGE_REQ = 3003,
|
||||
@@ -117,6 +118,9 @@ template <> constexpr uint16_t get_packet_id<Ping>() {
|
||||
template <> constexpr uint16_t get_packet_id<Pong>() {
|
||||
return std::to_underlying(PacketEnum::PONG);
|
||||
}
|
||||
template <> constexpr uint16_t get_packet_id<PlayerWaterSound>() {
|
||||
return std::to_underlying(PacketEnum::PLAYER_WATER_SOUND);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires std::derived_from<T, google::protobuf::Message>
|
||||
|
||||
@@ -71,6 +71,7 @@ public:
|
||||
bool set_block(const glm::ivec3& block_pos, unsigned id);
|
||||
|
||||
void sync_player_pos(const C2S_PlayerInfo& rsp);
|
||||
void sync_player_water_sound(const PlayerWaterSound& rsp);
|
||||
void handle_player_login(const std::string& player_name,
|
||||
std::shared_ptr<Session> session);
|
||||
glm::vec3 get_player_pos(const std::string& uuid) const;
|
||||
@@ -156,7 +157,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;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
const TextureManager& texture_manager, DevPanel& dev_panel);
|
||||
~Renderer();
|
||||
void hot_reload();
|
||||
void init();
|
||||
void init(bool debug_on);
|
||||
const Shader& get_shader(const std::string& name) const;
|
||||
void render();
|
||||
void update(float delta_time);
|
||||
|
||||
@@ -104,6 +104,8 @@ inline float distance2(const glm::vec3& a, const glm::vec3& b) {
|
||||
return glm::dot(diff, diff);
|
||||
}
|
||||
|
||||
inline float lerp(float a, float b, float t) { return a + t * (b - a); }
|
||||
|
||||
} // namespace Math
|
||||
|
||||
} // namespace Cubed
|
||||
2
include/stb/.clang-format
Normal file
2
include/stb/.clang-format
Normal file
@@ -0,0 +1,2 @@
|
||||
DisableFormat: true
|
||||
SortIncludes: false
|
||||
5584
include/stb/stb_vorbis.h
Normal file
5584
include/stb/stb_vorbis.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user