Use targets HUD

This commit is contained in:
tovjemam 2026-03-22 18:00:07 +01:00
parent 7efa2e992a
commit db19733c82
15 changed files with 171 additions and 17 deletions

View File

@ -118,6 +118,8 @@ set(CLIENT_ONLY_SOURCES
"src/gui/font.cpp" "src/gui/font.cpp"
"src/gui/menu.hpp" "src/gui/menu.hpp"
"src/gui/menu.cpp" "src/gui/menu.cpp"
"src/gui/use_target_hud.hpp"
"src/gui/use_target_hud.cpp"
"src/utils/files.cpp" "src/utils/files.cpp"
) )

View File

@ -44,7 +44,7 @@ void App::Frame()
params.env.clear_color = glm::vec3(0.1f); params.env.clear_color = glm::vec3(0.1f);
dlist_.Clear(); dlist_.Clear();
gui_.Begin(); gui_.Begin(viewport_size_);
// draw session // draw session
if (session_) if (session_)

View File

@ -40,7 +40,7 @@ public:
void Input(game::PlayerInputType in, bool pressed, bool repeated); void Input(game::PlayerInputType in, bool pressed, bool repeated);
void MouseMove(const glm::vec2& delta); void MouseMove(const glm::vec2& delta);
float GetTime() const { return time_; } const float& GetTime() const { return time_; }
float GetDeltaTime() const { return delta_time_; } float GetDeltaTime() const { return delta_time_; }
game::view::ClientSession* GetSession() { return session_.get(); } game::view::ClientSession* GetSession() { return session_.get(); }

View File

@ -69,6 +69,14 @@ void game::Player::SendChat(const std::string& text)
msg.Write(chatm); msg.Write(chatm);
} }
void game::Player::SetUseTarget(const std::string& text, const std::string& error_text, float delay)
{
auto msg = BeginMsg(net::MSG_USETARGET);
msg.Write(net::UseTargetName(text));
msg.Write(net::UseTargetName(error_text));
msg.Write<net::UseDelayQ>(delay);
}
game::Player::~Player() game::Player::~Player()
{ {
game_.PlayerLeft(*this); game_.PlayerLeft(*this);

View File

@ -32,6 +32,7 @@ public:
void SetCamera(net::EntNum entnum); void SetCamera(net::EntNum entnum);
void SendChat(const std::string& text); void SendChat(const std::string& text);
void SetUseTarget(const std::string& text, const std::string& error_text, float delay);
const std::string& GetName() const { return name_; } const std::string& GetName() const { return name_; }

View File

@ -164,16 +164,13 @@ void game::PlayerCharacter::SendUseTargetInfo()
if (!use_target_) if (!use_target_)
{ {
player_->SendChat("už nejde nic použít"); player_->SetUseTarget(std::string(), std::string(), 0.0f);
return; return;
} }
std::string msg = "[E] " + use_target_->desc; std::string error_text;
if (use_error_)
error_text = use_error_;
if (using_) player_->SetUseTarget(use_target_->desc, error_text, using_ ? use_delay_ - use_progress_ : 0.0f);
{
msg += " (zbývá " + std::to_string(use_delay_ - use_progress_) + ")";
}
player_->SendChat(msg);
} }

View File

@ -26,6 +26,7 @@ public:
private: private:
void UpdateInputs(); void UpdateInputs();
void UpdateUseTarget(); void UpdateUseTarget();
void UseChanged(bool enabled); void UseChanged(bool enabled);
void SendUseTargetInfo(); void SendUseTargetInfo();

View File

@ -7,7 +7,7 @@
#include "vehicleview.hpp" #include "vehicleview.hpp"
#include "utils/version.hpp" #include "utils/version.hpp"
game::view::ClientSession::ClientSession(App& app) : app_(app) game::view::ClientSession::ClientSession(App& app) : app_(app), use_target_hud_(app.GetTime())
{ {
// send login // send login
auto msg = BeginMsg(net::MSG_ID); auto msg = BeginMsg(net::MSG_ID);
@ -46,6 +46,9 @@ bool game::view::ClientSession::ProcessSingleMessage(net::MessageType type, net:
case net::MSG_CHAT: case net::MSG_CHAT:
return ProcessChatMsg(msg); return ProcessChatMsg(msg);
case net::MSG_USETARGET:
return ProcessUseTargetMsg(msg);
default: default:
// try pass the msg to world // try pass the msg to world
if (world_ && world_->ProcessMsg(type, msg)) if (world_ && world_->ProcessMsg(type, msg))
@ -97,6 +100,8 @@ void game::view::ClientSession::Draw(gfx::DrawList& dlist, gfx::DrawListParams&
{ {
DrawWorld(dlist, params, gui); DrawWorld(dlist, params, gui);
} }
use_target_hud_.Draw(gui);
} }
void game::view::ClientSession::GetViewInfo(glm::vec3& eye, glm::mat4& view) const void game::view::ClientSession::GetViewInfo(glm::vec3& eye, glm::mat4& view) const
@ -166,6 +171,18 @@ bool game::view::ClientSession::ProcessChatMsg(net::InMessage& msg)
return true; return true;
} }
bool game::view::ClientSession::ProcessUseTargetMsg(net::InMessage& msg)
{
net::UseTargetName text, error_text;
float delay;
if (!msg.Read(text) || !msg.Read(error_text) || !msg.Read<net::UseDelayQ>(delay))
return false;
use_target_hud_.SetData(text, error_text, delay);
return true;
}
void game::view::ClientSession::DrawWorld(gfx::DrawList& dlist, gfx::DrawListParams& params, gui::Context& gui) void game::view::ClientSession::DrawWorld(gfx::DrawList& dlist, gfx::DrawListParams& params, gui::Context& gui)
{ {
// glm::mat4 view = glm::lookAt(glm::vec3(15.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, -13.0f), glm::vec3(0.0f, // glm::mat4 view = glm::lookAt(glm::vec3(15.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, -13.0f), glm::vec3(0.0f,

View File

@ -10,6 +10,7 @@
#include "net/inmessage.hpp" #include "net/inmessage.hpp"
#include "net/msg_producer.hpp" #include "net/msg_producer.hpp"
#include "game/player_input.hpp" #include "game/player_input.hpp"
#include "gui/use_target_hud.hpp"
class App; class App;
@ -39,6 +40,7 @@ private:
bool ProcessWorldMsg(net::InMessage& msg); bool ProcessWorldMsg(net::InMessage& msg);
bool ProcessCameraMsg(net::InMessage& msg); bool ProcessCameraMsg(net::InMessage& msg);
bool ProcessChatMsg(net::InMessage& msg); bool ProcessChatMsg(net::InMessage& msg);
bool ProcessUseTargetMsg(net::InMessage& msg);
void DrawWorld(gfx::DrawList& dlist, gfx::DrawListParams& params, gui::Context& gui); void DrawWorld(gfx::DrawList& dlist, gfx::DrawListParams& params, gui::Context& gui);
@ -56,6 +58,8 @@ private:
net::ViewYawQ view_yaw_q_; net::ViewYawQ view_yaw_q_;
net::ViewPitchQ view_pitch_q_; net::ViewPitchQ view_pitch_q_;
float last_send_time_ = 0.0f; float last_send_time_ = 0.0f;
gui::UseTargetHud use_target_hud_;
}; };
} // namespace game::view } // namespace game::view

View File

@ -10,11 +10,13 @@ gui::Context::Context(gfx::DrawList& dlist, std::shared_ptr<const Font> default_
white_tex_ = assets::CacheManager::GetTexture("data/white.png"); white_tex_ = assets::CacheManager::GetTexture("data/white.png");
} }
void gui::Context::Begin() void gui::Context::Begin(const glm::vec2& viewport_size)
{ {
vertices_.clear(); vertices_.clear();
indices_.clear(); indices_.clear();
ranges_.clear(); ranges_.clear();
viewport_size_ = viewport_size;
} }
void gui::Context::DrawRect(const glm::vec2& p0, const glm::vec2& p1, uint32_t color) void gui::Context::DrawRect(const glm::vec2& p0, const glm::vec2& p1, uint32_t color)

View File

@ -32,7 +32,7 @@ class Context
public: public:
Context(gfx::DrawList& dlist, std::shared_ptr<const Font> default_font); Context(gfx::DrawList& dlist, std::shared_ptr<const Font> default_font);
void Begin(); void Begin(const glm::vec2& viewport_size);
void DrawRect(const glm::vec2& p0, const glm::vec2& p1, uint32_t color); void DrawRect(const glm::vec2& p0, const glm::vec2& p1, uint32_t color);
@ -43,6 +43,8 @@ public:
void Render(); void Render();
const std::shared_ptr<const Font>& GetFont() const { return font_; } const std::shared_ptr<const Font>& GetFont() const { return font_; }
const glm::vec2& GetViewportSize() const { return viewport_size_; }
private: private:
void BeginTexture(const gfx::Texture* texture); void BeginTexture(const gfx::Texture* texture);
@ -61,7 +63,7 @@ private:
std::vector<uint32_t> indices_; std::vector<uint32_t> indices_;
std::vector<GuiRange> ranges_; std::vector<GuiRange> ranges_;
glm::vec2 viewport_size_ = glm::vec2(1.0f);
}; };

View File

@ -0,0 +1,87 @@
#include "use_target_hud.hpp"
gui::UseTargetHud::UseTargetHud(const float& time) : time_(time) {}
void gui::UseTargetHud::SetData(std::string text, std::string error_text, float delay)
{
text_ = std::move(text);
if (error_text.empty())
error_text_.clear();
else
error_text_ = "(" + error_text + ")";
start_time_ = time_;
end_time_ = delay > 0.01f ? start_time_ + delay : start_time_;
}
void gui::UseTargetHud::Draw(Context& ctx) const
{
if (text_.empty())
return;
bool active = start_time_ != end_time_;
const float spacing = 20.0f;
glm::vec2 key_size(30.0f);
glm::vec2 text_size = ctx.MeasureText(text_);
float total_width = key_size.x + spacing + text_size.x;
glm::vec2 error_size(0.0f);
if (!error_text_.empty())
{
error_size = ctx.MeasureText(error_text_);
total_width += spacing + error_size.x;
}
glm::vec2 progress_size(60.0f, 10.0f);
if (active)
{
total_width += spacing + progress_size.x;
}
auto& viewport_size = ctx.GetViewportSize();
float center_x = viewport_size.x * 0.5f;
float center_y = viewport_size.y - 50.0f;
float x = center_x - total_width * 0.5f;
// draw key bg
glm::vec2 bg_p0(x, center_y - key_size.y * 0.5f);
glm::vec2 bg_p1 = bg_p0 + key_size;
ctx.DrawRect(bg_p0, bg_p1, 0x77000000);
// draw key text
static constexpr std::string_view key_text = "E";
ctx.DrawTextAligned(key_text, bg_p0 + key_size * 0.5f, glm::vec2(-0.5f, -0.5f));
x += key_size.x + spacing;
// draw text
glm::vec2 text_p(x, center_y - text_size.y * 0.5f);
ctx.DrawText(text_, text_p);
x += text_size.x + spacing;
// draw error text
if (!error_text_.empty())
{
glm::vec2 error_text_p(x, center_y - error_size.y * 0.5f);
ctx.DrawText(error_text_, error_text_p);
x += error_size.x + spacing;
}
// draw progress bar
if (active)
{
float t = (time_ - start_time_) / (end_time_ - start_time_);
t = glm::clamp(t, 0.0f, 1.0f);
glm::vec2 progress_p0(x, center_y - progress_size.y * 0.5f);
glm::vec2 progress_p1 = progress_p0 + progress_size;
glm::vec2 progress_p1_bar = progress_p0 + glm::vec2(t * progress_size.x, progress_size.y);
ctx.DrawRect(progress_p0, progress_p1, 0x77000000);
ctx.DrawRect(progress_p0, progress_p1_bar, 0xFF00FFFF);
}
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <string>
#include "context.hpp"
namespace gui
{
class UseTargetHud
{
public:
UseTargetHud(const float& time);
void SetData(std::string text, std::string error_text, float delay);
void Draw(Context& ctx) const;
private:
const float& time_;
std::string text_;
std::string error_text_;
float start_time_ = 0.0f;
float end_time_ = 0.0f;
};
}

View File

@ -34,6 +34,9 @@ enum MessageType : uint8_t
// CAM <EntNum> // CAM <EntNum>
MSG_CAM, MSG_CAM,
// USETARGET ...
MSG_USETARGET,
/*~~~~~~~~ Entity ~~~~~~~~*/ /*~~~~~~~~ Entity ~~~~~~~~*/
// ENTSPAWN <EntNum> <EntType> data... // ENTSPAWN <EntNum> <EntType> data...
MSG_ENTSPAWN, MSG_ENTSPAWN,
@ -132,11 +135,13 @@ using ObjCount = ObjNum;
using NumTexels = uint16_t; using NumTexels = uint16_t;
// version // version
using Version = uint32_t; using Version = uint32_t;
// tuning // tuning
using TuningPartIdx = uint8_t; using TuningPartIdx = uint8_t;
// use target
using UseTargetName = FixedStr<128>;
using UseDelayQ = Quantized<uint8_t, 0, 10>;
} // namespace net } // namespace net

View File

@ -1,3 +1,3 @@
#pragma once #pragma once
#define FEKAL_VERSION 2026032101 #define FEKAL_VERSION 2026032201