From 915620bb4e6ec07526db822e05bb3b92b45f456b Mon Sep 17 00:00:00 2001 From: tovjemam Date: Sun, 29 Mar 2026 01:07:45 +0100 Subject: [PATCH] Basic tuning --- CMakeLists.txt | 2 + src/assets/cmdfile.cpp | 6 ++ src/game/enterable_world.hpp | 4 + src/game/game.cpp | 72 +++++++++++++--- src/game/game.hpp | 5 ++ src/game/tuning_world.cpp | 159 +++++++++++++++++++++++++++++++++++ src/game/tuning_world.hpp | 58 +++++++++++++ src/game/vehicle.cpp | 8 ++ src/game/vehicle.hpp | 2 + src/gameview/vehicleview.cpp | 2 + src/net/defs.hpp | 1 + src/utils/colors.hpp | 17 ++++ 12 files changed, 326 insertions(+), 10 deletions(-) create mode 100644 src/game/tuning_world.cpp create mode 100644 src/game/tuning_world.hpp create mode 100644 src/utils/colors.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5126add..2995284 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,6 +154,8 @@ set(SERVER_ONLY_SOURCES "src/game/remote_menu.cpp" "src/game/simple_entity.hpp" "src/game/simple_entity.cpp" + "src/game/tuning_world.hpp" + "src/game/tuning_world.cpp" "src/game/usable.hpp" "src/game/vehicle.hpp" "src/game/vehicle.cpp" diff --git a/src/assets/cmdfile.cpp b/src/assets/cmdfile.cpp index ff1c854..c6f1b03 100644 --- a/src/assets/cmdfile.cpp +++ b/src/assets/cmdfile.cpp @@ -42,6 +42,12 @@ std::string assets::ParseString(std::istringstream& iss) str = str.substr(1); + if (str.ends_with('"')) + { + str.pop_back(); + return str; + } + while (iss) { std::string tmp; diff --git a/src/game/enterable_world.hpp b/src/game/enterable_world.hpp index a91eb5b..66685a7 100644 --- a/src/game/enterable_world.hpp +++ b/src/game/enterable_world.hpp @@ -21,6 +21,10 @@ public: virtual void PlayerViewAnglesChanged(Player& player, float yaw, float pitch); virtual void RemovePlayer(Player& player); + virtual void OnVehicleJoined(DrivableVehicle& vehicle) {} + + virtual void OnPlayerLeaving(Player& player) {} + PlayerCharacter* GetPlayerCharacter(Player& player); private: diff --git a/src/game/game.cpp b/src/game/game.cpp index 8080b1e..5cdcb54 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -5,7 +5,7 @@ #include "player_character.hpp" static constexpr glm::vec3 openworld_spawn(100.0f, 100.0f, 1.0f); -static constexpr glm::vec3 test_spawn(0.0f, 0.0f, 1.0f); +static constexpr glm::vec3 test_spawn(0.0f, 0.0f, 0.1f); static uint32_t GetRandomColor24() { @@ -23,6 +23,9 @@ game::Game::Game() testworld_ = std::make_shared("testarena"); all_worlds_.push_back(testworld_.get()); + + garage_ = std::make_shared(*this, *openworld_, glm::vec3(0.0f), 0.0f, "garage"); + all_worlds_.push_back(garage_.get()); } void game::Game::Update() @@ -72,16 +75,18 @@ void game::Game::PlayerInput(Player& player, PlayerInputType type, bool enabled) if (!enabled) return; - auto& player_info = players_.at(&player); + // auto& player_info = players_.at(&player); - if (player_info.world == openworld_.get()) - { - MovePlayerToWorld(player_info, testworld_.get(), test_spawn, 0.0f, true); - } - else - { - MovePlayerToWorld(player_info, openworld_.get(), openworld_spawn, 0.0f, true); - } + // if (player_info.world == openworld_.get()) + // { + // MovePlayerToWorld(player_info, testworld_.get(), test_spawn, 0.0f, true); + // } + // else + // { + // MovePlayerToWorld(player_info, openworld_.get(), openworld_spawn, 0.0f, true); + // } + + MovePlayerToTuning(player); break; } @@ -103,6 +108,11 @@ void game::Game::PlayerInput(Player& player, PlayerInputType type, bool enabled) void game::Game::PlayerLeft(Player& player) { auto world = FindPlayerWorld(player); + if (world) + world->OnPlayerLeaving(player); + + // find again as may have changed + world = FindPlayerWorld(player); if (world) world->RemovePlayer(player); @@ -111,6 +121,13 @@ void game::Game::PlayerLeft(Player& player) BroadcastChat(player.GetName() + "^r se vodpojil zmrd"); } +void game::Game::MovePlayerToWorld(Player& player, EnterableWorld& world, bool with_vehicle, const glm::vec3& pos, + float yaw) +{ + auto& player_info = GetPlayerInfo(player); + MovePlayerToWorld(player_info, &world, pos, yaw, true); +} + void game::Game::BroadcastChat(const std::string& text) { for (auto& [player, info] : players_) @@ -168,6 +185,8 @@ void game::Game::MoveVehicleToWorld(DrivableVehicle& vehicle, EnterableWorld& ne } vehicle.Remove(); + + new_world.OnVehicleJoined(new_vehicle); } void game::Game::MovePlayerToWorld(PlayerGameInfo& player_info, EnterableWorld* new_world, const glm::vec3& pos, @@ -238,3 +257,36 @@ void game::Game::DisplayTestMenu(Player& player) }); } + +void game::Game::MovePlayerToTuning(Player& player) +{ + auto& player_info = GetPlayerInfo(player); + + if (player_info.world != openworld_.get()) + return; + + if (garage_->IsOccupied()) + { + player.SendChat("bohužel tam teď oxiduje nějakej píčus " + garage_->GetOccupantName() + "^r!"); + return; + } + + auto character = player_info.world->GetPlayerCharacter(player); + if (!character) + return; + + auto vehicle = character->GetVehicle(); + if (!vehicle) + { + player.SendChat("nemáš vehikl!!!"); + return; + } + + if (vehicle->GetPassenger(0) != character) + { + player.SendChat("nejsi ridič!!"); + return; + } + + MovePlayerToWorld(player_info, garage_.get(), glm::vec3(0.0f), 0.0f, true); +} diff --git a/src/game/game.hpp b/src/game/game.hpp index 94d3850..6bc2ecf 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -3,6 +3,7 @@ #include #include "enterable_world.hpp" +#include "tuning_world.hpp" #include "openworld.hpp" namespace game @@ -31,6 +32,8 @@ public: void PlayerInput(Player& player, PlayerInputType type, bool enabled); void PlayerLeft(Player& player); + void MovePlayerToWorld(Player& player, EnterableWorld& world, bool with_vehicle, const glm::vec3& pos, float yaw); + private: void BroadcastChat(const std::string& text); @@ -43,10 +46,12 @@ private: EnterableWorld* FindPlayerWorld(Player& player) const; void DisplayTestMenu(Player& player); + void MovePlayerToTuning(Player& player); private: std::shared_ptr openworld_; std::shared_ptr testworld_; + std::shared_ptr garage_; std::vector all_worlds_; // for common update etc. std::map players_; diff --git a/src/game/tuning_world.cpp b/src/game/tuning_world.cpp new file mode 100644 index 0000000..34625db --- /dev/null +++ b/src/game/tuning_world.cpp @@ -0,0 +1,159 @@ +#include "tuning_world.hpp" +#include "player_character.hpp" +#include "utils/colors.hpp" +#include "assets/vehicle_tuning_list.hpp" +#include "game.hpp" + +game::TuningWorld::TuningWorld(Game& game, EnterableWorld& exit_world, const glm::vec3& exit_pos, float exit_yaw, std::string mapname) : + Super(std::move(mapname)), game_(game), exit_world_(exit_world), exit_pos_(exit_pos), exit_yaw_(exit_yaw) +{ +} + +void game::TuningWorld::PlayerInput(Player& player, PlayerInputType type, bool enabled) +{ + if (&player == player_ || !enabled || type != IN_USE) + return; + + // passenger wants exit + game_.MovePlayerToWorld(player, exit_world_, false, exit_pos_, exit_yaw_); +} + +void game::TuningWorld::OnVehicleJoined(DrivableVehicle& vehicle) +{ + if (IsOccupied()) + throw std::runtime_error("vehicle joined to occupied tuning garage"); + + auto driver = dynamic_cast(vehicle.GetPassenger(0)); + if (!driver) + throw std::runtime_error("vehicle joined to tuning without player driver??"); + + auto player = driver->GetPlayer(); + if (!player) + throw std::runtime_error("vehicle joined to tuning without ACTIVE player driver??"); + + vehicle_ = &vehicle; + tuning_list_ = &vehicle.GetModel()->GetTuningList(); + player_ = player; + + Setup(); +} + +void game::TuningWorld::OnPlayerLeaving(Player& player) +{ + if (&player != player_) + return; + + Reset(); +} + +void game::TuningWorld::Setup() +{ + tuning_ = vehicle_->GetTuning(); + UpdateTuningVals(); + DisplayTuningMenu(); +} + +void game::TuningWorld::UpdateTuningVals() +{ + tun_primary_color_ = ColorU32ToU8Vec3(tuning_.primary_color); + + tun_wheel_idx_ = tuning_.wheels_idx; + tun_wheel_color_ = ColorU32ToU8Vec3(tuning_.wheel_color); +} + +void game::TuningWorld::UpdateTuning() +{ + tuning_.primary_color = ColorU8Vec3ToU32(tun_primary_color_); + + tuning_.wheels_idx = tun_wheel_idx_; + tuning_.wheel_color = ColorU8Vec3ToU32(tun_wheel_color_); + + vehicle_->SetTuning(tuning_); +} + +static void AddColorChannelSlider(game::RemoteMenu& menu, uint8_t& ch, std::string name, std::function on_change) +{ + auto& slider = menu.AddItem(game::RM_SELECT, std::move(name)); + + auto on_select = [&slider, &ch, on_change = std::move(on_change)] (int dir) { + int new_val = ch + dir * 5; + if (new_val < 0) + ch = 0; + else if (new_val > 255) + ch = 255; + else + ch = new_val; + + slider.SetSelection(std::to_string(ch)); + on_change(); + }; + + on_select(0); + slider.SetOnSelect(on_select); +} + +static void AddColorSliders(game::RemoteMenu& menu, glm::u8vec3& color, std::string name, std::function on_change) +{ + AddColorChannelSlider(menu, color.r, name + " ^f00R", on_change); + AddColorChannelSlider(menu, color.g, name + " ^0f0G", on_change); + AddColorChannelSlider(menu, color.b, name + " ^00fB", on_change); +} + +static void AddWheelTypeSlider(game::RemoteMenu& menu, const assets::VehicleTuningList& tuning_list, size_t& idx, std::function on_change) +{ + auto& slider = menu.AddItem(game::RM_SELECT, "kola"); + + auto on_select = [&slider, &idx, &tuning_list, on_change = std::move(on_change)] (int dir) { + auto& wheels = tuning_list.wheels; + + if (dir < 0 && idx == 0) + return; + + if (dir > 0 && (idx + 1) >= wheels.size()) + return; + + idx += dir; + + slider.SetSelection(tuning_list.wheels[idx].displayname); + on_change(); + }; + + on_select(0); + slider.SetOnSelect(on_select); +} + +void game::TuningWorld::DisplayTuningMenu() +{ + // display menu + auto& menu = player_->DisplayMenu("tuning"); + menu_ = &menu; + + auto on_change = [this] { UpdateTuning(); }; + + AddColorSliders(menu, tun_primary_color_, "primární", on_change); + + if (!tuning_list_->wheels.empty()) + { + AddWheelTypeSlider(menu, *tuning_list_, tun_wheel_idx_, on_change); + AddColorSliders(menu, tun_wheel_color_, "kola", on_change); + } + + auto& exit_btn = menu.AddItem(RM_BUTTON, "vylézt"); + exit_btn.SetOnClick([this] { + Reset(); + }); +} + +void game::TuningWorld::Reset() +{ + if (player_) + { + player_->CloseMenu(*menu_); + game_.MovePlayerToWorld(*player_, exit_world_, true, exit_pos_, exit_yaw_); + } + + player_ = nullptr; + vehicle_ = nullptr; + tuning_list_ = nullptr; + menu_ = nullptr; +} diff --git a/src/game/tuning_world.hpp b/src/game/tuning_world.hpp new file mode 100644 index 0000000..0c6732f --- /dev/null +++ b/src/game/tuning_world.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include "enterable_world.hpp" +#include "drivable_vehicle.hpp" + +namespace game +{ + +class Game; +class RemoteMenu; + +class TuningWorld : public EnterableWorld +{ +public: + using Super = EnterableWorld; + + TuningWorld(Game& game, EnterableWorld& exit_world, const glm::vec3& exit_pos, float exit_yaw, std::string mapname); + + virtual void PlayerInput(Player& player, PlayerInputType type, bool enabled); + virtual void OnVehicleJoined(DrivableVehicle& vehicle); + virtual void OnPlayerLeaving(Player& player); + + bool IsOccupied() const { return player_ != nullptr; } + const std::string& GetOccupantName() const { return player_->GetName(); } + +private: + void Setup(); + + void UpdateTuningVals(); + void UpdateTuning(); + + void DisplayTuningMenu(); + + void Reset(); + +private: + Game& game_; + EnterableWorld& exit_world_; + glm::vec3 exit_pos_; + float exit_yaw_; + + // active player + Player* player_ = nullptr; + DrivableVehicle* vehicle_ = nullptr; + const assets::VehicleTuningList* tuning_list_ = nullptr; + + game::RemoteMenu* menu_ = nullptr; + + VehicleTuning tuning_; + + + glm::u8vec3 tun_primary_color_; + size_t tun_wheel_idx_; + glm::u8vec3 tun_wheel_color_; + +}; + +} \ No newline at end of file diff --git a/src/game/vehicle.cpp b/src/game/vehicle.cpp index 0aea9e8..f07965a 100644 --- a/src/game/vehicle.cpp +++ b/src/game/vehicle.cpp @@ -201,6 +201,14 @@ void game::Vehicle::SetSteering(bool analog, float value) target_steering_ = value; } +void game::Vehicle::SetTuning(const VehicleTuning& tuning) +{ + tuning_ = tuning; + + auto msg = BeginEntMsg(net::EMSG_TUNING); + WriteTuning(msg); +} + game::Vehicle::~Vehicle() { auto& bt_world = world_.GetBtWorld(); diff --git a/src/game/vehicle.hpp b/src/game/vehicle.hpp index 2805819..c72a46b 100644 --- a/src/game/vehicle.hpp +++ b/src/game/vehicle.hpp @@ -56,6 +56,8 @@ public: void SetSteering(bool analog, float value = 0.0f); + void SetTuning(const VehicleTuning& tuning); + const std::string& GetModelName() const { return tuning_.model; } const std::shared_ptr& GetModel() const { return model_; } const VehicleTuning& GetTuning() const { return tuning_; } diff --git a/src/gameview/vehicleview.cpp b/src/gameview/vehicleview.cpp index 5bdd57f..039ffbb 100644 --- a/src/gameview/vehicleview.cpp +++ b/src/gameview/vehicleview.cpp @@ -45,6 +45,8 @@ bool game::view::VehicleView::ProcessMsg(net::EntMsgType type, net::InMessage& m { case net::EMSG_DEFORM: return ProcessDeformMsg(msg); + case net::EMSG_TUNING: + return ReadTuning(msg); default: return Super::ProcessMsg(type, msg); } diff --git a/src/net/defs.hpp b/src/net/defs.hpp index 5801280..a1a36f8 100644 --- a/src/net/defs.hpp +++ b/src/net/defs.hpp @@ -100,6 +100,7 @@ enum EntMsgType : uint8_t // EMSG_UPDATE, // deprecated EMSG_PLAYSOUND, EMSG_DEFORM, + EMSG_TUNING, }; using PositionElemQ = Quantized; diff --git a/src/utils/colors.hpp b/src/utils/colors.hpp new file mode 100644 index 0000000..53b3d0a --- /dev/null +++ b/src/utils/colors.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +inline glm::u8vec3 ColorU32ToU8Vec3(uint32_t color) +{ + return glm::u8vec3( + color & 0xFF, + (color >> 8) & 0xFF, + (color >> 16) & 0xFF + ); +} + +inline uint32_t ColorU8Vec3ToU32(const glm::u8vec3& color) +{ + return 0xFF000000 | (color.b << 16) | (color.g << 8) | color.r; +} \ No newline at end of file