diff --git a/CMakeLists.txt b/CMakeLists.txt index a896996..643832d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,8 @@ set(CLIENT_ONLY_SOURCES "src/assets/effect.cpp" "src/assets/mesh_builder.hpp" "src/assets/mesh_builder.cpp" + "src/assets/precache.hpp" + "src/assets/precache.cpp" "src/audio/defs.hpp" "src/audio/master.hpp" "src/audio/master.cpp" @@ -135,6 +137,8 @@ set(CLIENT_ONLY_SOURCES "src/gui/context.cpp" "src/gui/font.hpp" "src/gui/font.cpp" + "src/gui/loading_screen.hpp" + "src/gui/loading_screen.cpp" "src/gui/menu.hpp" "src/gui/menu.cpp" "src/gui/player_hud.hpp" diff --git a/src/assets/precache.cpp b/src/assets/precache.cpp new file mode 100644 index 0000000..27d5a0a --- /dev/null +++ b/src/assets/precache.cpp @@ -0,0 +1,45 @@ +#include "precache.hpp" + +#include "cmdfile.hpp" +#include "cache.hpp" + +assets::Precache::Precache(const std::string& path) +{ + LoadCMDFile(path, [this](const std::string& command, std::istringstream& iss) { + std::string name; + iss >> name; + items_.emplace_back(PrecacheItem{command, name}); + }); +} + +static std::any LoadItem(const assets::PrecacheItem& item) +{ + if (item.type == "fx") + return assets::CacheManager::GetEffect("data/" + item.name + ".fx"); + else if (item.type == "font") + return assets::CacheManager::GetFont("data/" + item.name + ".font"); + else if (item.type == "item") + return assets::CacheManager::GetItem("data/" + item.name + ".item"); + else if (item.type == "map") + return assets::CacheManager::GetMap("data/" + item.name + ".map"); + else if (item.type == "model") + return assets::CacheManager::GetModel("data/" + item.name + ".mdl"); + else if (item.type == "skeleton") + return assets::CacheManager::GetSkeleton("data/" + item.name + ".sk"); + else if (item.type == "sound") + return assets::CacheManager::GetSound("data/" + item.name + ".snd"); + else if (item.type == "texture") + return assets::CacheManager::GetTexture("data/" + item.name + ".png"); + else if (item.type == "vehicle") + return assets::CacheManager::GetVehicleModel("data/" + item.name + ".veh"); +} + +void assets::Precache::LoadNext() +{ + if (IsDone()) + return; + + refs_.emplace_back(LoadItem(items_[num_loaded_])); + ++num_loaded_; +} + diff --git a/src/assets/precache.hpp b/src/assets/precache.hpp new file mode 100644 index 0000000..7323da5 --- /dev/null +++ b/src/assets/precache.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +namespace assets +{ + +struct PrecacheItem +{ + std::string type; + std::string name; +}; + +class Precache +{ +public: + Precache(const std::string& path); + + void LoadNext(); + + size_t GetNumItems() const { return items_.size(); } + size_t GetNumLoaded() const { return num_loaded_; } + bool IsDone() const { return GetNumLoaded() >= GetNumItems(); }; + +private: + std::vector items_; + size_t num_loaded_ = 0; + std::vector refs_; +}; + +} \ No newline at end of file diff --git a/src/client/app.cpp b/src/client/app.cpp index a5c3348..b00af5a 100644 --- a/src/client/app.cpp +++ b/src/client/app.cpp @@ -7,9 +7,10 @@ #include "assets/cache.hpp" #include "gameview/worldview.hpp" #include "gameview/utils.hpp" +#include "gui/loading_screen.hpp" App::App() : - gui_(dlist_, assets::CacheManager::GetFont("data/comic32.font")) + gui_(dlist_, assets::CacheManager::GetFont("data/comic32.font")), precache_("data/precache") { std::cout << "Initializing App..." << std::endl; @@ -110,6 +111,12 @@ void App::Draw() session_->Draw(dlist_, params, gui_); } + // loading screen + if (!precache_.IsDone()) + { + gui::DrawLoadingScreen(gui_, precache_.GetNumLoaded() * 100 / precache_.GetNumItems()); + } + DrawStats(); DrawChat(); @@ -370,7 +377,12 @@ AppState App::CheckStateTransition() return APP_STATE_LOADING; case APP_STATE_LOADING: - return APP_STATE_IDLE; + if (precache_.IsDone()) + return APP_STATE_IDLE; + + precache_.LoadNext(); + + return APP_STATE_LOADING; case APP_STATE_IDLE: return APP_STATE_CONNECT; diff --git a/src/client/app.hpp b/src/client/app.hpp index 2874277..90b94a0 100644 --- a/src/client/app.hpp +++ b/src/client/app.hpp @@ -13,6 +13,7 @@ #include "gui/menu.hpp" #include "gameview/client_session.hpp" #include "wsclient.hpp" +#include "assets/precache.hpp" struct ChatMessage { @@ -101,6 +102,8 @@ private: bool connected_ = false; bool local_error_ = false; + assets::Precache precache_; + std::unique_ptr session_; std::deque chat_; diff --git a/src/gameview/worldview.cpp b/src/gameview/worldview.cpp index e01666c..33c2dbe 100644 --- a/src/gameview/worldview.cpp +++ b/src/gameview/worldview.cpp @@ -9,6 +9,7 @@ #include "client_session.hpp" #include "draw_args.hpp" #include "net/utils.hpp" +#include "gui/loading_screen.hpp" game::view::WorldView::WorldView(ClientSession& session, net::InMessage& msg) : session_(session), audiomaster_(session_.GetAudioMaster()), audioplayer_(audiomaster_), emitter_(&audioplayer_) @@ -33,52 +34,6 @@ game::view::WorldView::WorldView(ClientSession& session, net::InMessage& msg) : map_->EnableObj(objnum, false); } - // break sounds - Cache(assets::CacheManager::GetSound("data/breakpatnik.snd")); - Cache(assets::CacheManager::GetSound("data/breaksign.snd")); - Cache(assets::CacheManager::GetSound("data/breakwindow.snd")); - Cache(assets::CacheManager::GetSound("data/breakwood.snd")); - Cache(assets::CacheManager::GetSound("data/cardoor.snd")); - Cache(assets::CacheManager::GetSound("data/crash.snd")); - - // vehicles - Cache(assets::CacheManager::GetVehicleModel("data/avia.veh")); - Cache(assets::CacheManager::GetVehicleModel("data/passat.veh")); - Cache(assets::CacheManager::GetVehicleModel("data/pickup_hd.veh")); - Cache(assets::CacheManager::GetVehicleModel("data/polskifiat.veh")); - Cache(assets::CacheManager::GetVehicleModel("data/twingo.veh")); - - // models - Cache(assets::CacheManager::GetModel("data/marker_base.mdl")); - Cache(assets::CacheManager::GetModel("data/marker_tuning.mdl")); - - // items - Cache(assets::CacheManager::GetItem("data/airrifle.item")); - Cache(assets::CacheManager::GetItem("data/airsniper.item")); - Cache(assets::CacheManager::GetItem("data/ak47.item")); - Cache(assets::CacheManager::GetItem("data/uzi.item")); - - // fire sounds - Cache(assets::CacheManager::GetSound("data/airrifle_fire.snd")); - Cache(assets::CacheManager::GetSound("data/ak_fire.snd")); - Cache(assets::CacheManager::GetSound("data/uzi_fire.snd")); - - // other sounds - Cache(assets::CacheManager::GetSound("data/pickup_ammo.snd")); - Cache(assets::CacheManager::GetSound("data/cow-01.snd")); - Cache(assets::CacheManager::GetSound("data/cow-02.snd")); - Cache(assets::CacheManager::GetSound("data/cow-04.snd")); - Cache(assets::CacheManager::GetSound("data/cow-05.snd")); - - // fx - Cache(assets::CacheManager::GetEffect("data/firefx.fx")); - Cache(assets::CacheManager::GetEffect("data/impact_dirt.fx")); - Cache(assets::CacheManager::GetEffect("data/impact_flesh.fx")); - Cache(assets::CacheManager::GetEffect("data/impact_grass.fx")); - Cache(assets::CacheManager::GetEffect("data/impact_metal.fx")); - Cache(assets::CacheManager::GetEffect("data/impact_stone.fx")); - Cache(assets::CacheManager::GetEffect("data/impact_wood.fx")); - env_ = std::make_unique(); env_->SetDayTime(12.0f); } @@ -141,7 +96,7 @@ void game::view::WorldView::Draw(const DrawArgs& args) { if (!map_->IsLoaded()) { - DrawLoadingScreen(args); + gui::DrawLoadingScreen(args.gui, map_->GetLoadingPercent()); return; } @@ -173,22 +128,6 @@ bool game::view::WorldView::IsLoaded() const return map_ && map_->IsLoaded(); } -void game::view::WorldView::DrawLoadingScreen(const DrawArgs& args) const -{ - float margin = 50.0f; - glm::vec2 size(400.0f, 15.0f); - glm::vec2 pos(margin, args.screen_size.y - margin - size.y); - - int loaded_percent = map_->GetLoadingPercent(); - float loaded = static_cast(loaded_percent) * 0.01f; - - args.gui.DrawRect(pos, pos + size, 0x77FFFFFF); - args.gui.DrawRect(pos, pos + glm::vec2(size.x * loaded, size.y), 0xFF00FFFF); - - std::string load_text = std::to_string(loaded_percent) + "%"; - args.gui.DrawTextAligned(load_text, pos + glm::vec2(size.x + 50.0f, size.y * 0.5f), glm::vec2(-0.5f, -0.5f)); -} - void game::view::WorldView::UpdateEnv() { if (!env_) @@ -395,11 +334,6 @@ bool game::view::WorldView::ProcessFxMsg(net::InMessage& msg) } -void game::view::WorldView::Cache(std::any val) -{ - cache_.emplace_back(std::move(val)); -} - void game::view::WorldView::UpdateBeams() { beams_.erase(std::remove_if(beams_.begin(), beams_.end(), diff --git a/src/gameview/worldview.hpp b/src/gameview/worldview.hpp index b1dc92c..850fa9d 100644 --- a/src/gameview/worldview.hpp +++ b/src/gameview/worldview.hpp @@ -45,8 +45,6 @@ public: bool IsLoaded() const; private: - void DrawLoadingScreen(const DrawArgs& args) const; - void UpdateEnv(); void DrawEnv(const DrawArgs& args) const; @@ -60,8 +58,6 @@ private: bool ProcessBeamMsg(net::InMessage& msg); bool ProcessFxMsg(net::InMessage& msg); - void Cache(std::any val); - void UpdateBeams(); void DrawBeams(const DrawArgs& args) const; @@ -81,8 +77,6 @@ private: audio::Master& audiomaster_; audio::Player audioplayer_; // for non-entity sounds - std::vector cache_; - std::vector beams_; ParticleEmitter emitter_; diff --git a/src/gui/loading_screen.cpp b/src/gui/loading_screen.cpp new file mode 100644 index 0000000..aa4ee7f --- /dev/null +++ b/src/gui/loading_screen.cpp @@ -0,0 +1,16 @@ +#include "loading_screen.hpp" + +void gui::DrawLoadingScreen(Context& ctx, int percent) +{ + float margin = 50.0f; + glm::vec2 size(400.0f, 15.0f); + glm::vec2 pos(margin, ctx.GetViewportSize().y - margin - size.y); + + float loaded = static_cast(percent) * 0.01f; + + ctx.DrawRect(pos, pos + size, 0x77FFFFFF); + ctx.DrawRect(pos, pos + glm::vec2(size.x * loaded, size.y), 0xFF00FFFF); + + std::string load_text = std::to_string(percent) + "%"; + ctx.DrawTextAligned(load_text, pos + glm::vec2(size.x + 50.0f, size.y * 0.5f), glm::vec2(-0.5f, -0.5f)); +} diff --git a/src/gui/loading_screen.hpp b/src/gui/loading_screen.hpp new file mode 100644 index 0000000..ba81aec --- /dev/null +++ b/src/gui/loading_screen.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "context.hpp" + +namespace gui +{ + +void DrawLoadingScreen(Context& ctx, int percent); + +}