Basic tuning

This commit is contained in:
tovjemam 2026-03-29 01:07:45 +01:00
parent b69fe6d744
commit 915620bb4e
12 changed files with 326 additions and 10 deletions

View File

@ -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"

View File

@ -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;

View File

@ -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:

View File

@ -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<EnterableWorld>("testarena");
all_worlds_.push_back(testworld_.get());
garage_ = std::make_shared<TuningWorld>(*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);
}

View File

@ -3,6 +3,7 @@
#include <map>
#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> openworld_;
std::shared_ptr<EnterableWorld> testworld_;
std::shared_ptr<TuningWorld> garage_;
std::vector<World*> all_worlds_; // for common update etc.
std::map<Player*, PlayerGameInfo> players_;

159
src/game/tuning_world.cpp Normal file
View File

@ -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<PlayerCharacter*>(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<void()> 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<void()> 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<void()> 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;
}

58
src/game/tuning_world.hpp Normal file
View File

@ -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_;
};
}

View File

@ -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();

View File

@ -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<const assets::VehicleModel>& GetModel() const { return model_; }
const VehicleTuning& GetTuning() const { return tuning_; }

View File

@ -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);
}

View File

@ -100,6 +100,7 @@ enum EntMsgType : uint8_t
// EMSG_UPDATE, // deprecated
EMSG_PLAYSOUND,
EMSG_DEFORM,
EMSG_TUNING,
};
using PositionElemQ = Quantized<uint32_t, -10000, 10000, 1>;

17
src/utils/colors.hpp Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include <glm/glm.hpp>
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;
}