New vehicle tuning
This commit is contained in:
parent
26689b77a5
commit
bb81cd3605
@ -18,8 +18,6 @@ set(COMMON_SOURCES
|
|||||||
"src/assets/model.cpp"
|
"src/assets/model.cpp"
|
||||||
"src/assets/skeleton.hpp"
|
"src/assets/skeleton.hpp"
|
||||||
"src/assets/skeleton.cpp"
|
"src/assets/skeleton.cpp"
|
||||||
"src/assets/vehicle_tuning_list.hpp"
|
|
||||||
"src/assets/vehicle_tuning_list.cpp"
|
|
||||||
"src/assets/vehiclemdl.hpp"
|
"src/assets/vehiclemdl.hpp"
|
||||||
"src/assets/vehiclemdl.cpp"
|
"src/assets/vehiclemdl.cpp"
|
||||||
"src/collision/dynamicsworld.hpp"
|
"src/collision/dynamicsworld.hpp"
|
||||||
@ -157,6 +155,8 @@ set(SERVER_ONLY_SOURCES
|
|||||||
"src/game/tuning_world.hpp"
|
"src/game/tuning_world.hpp"
|
||||||
"src/game/tuning_world.cpp"
|
"src/game/tuning_world.cpp"
|
||||||
"src/game/usable.hpp"
|
"src/game/usable.hpp"
|
||||||
|
"src/game/vehicle_tuning.hpp"
|
||||||
|
"src/game/vehicle_tuning.cpp"
|
||||||
"src/game/vehicle.hpp"
|
"src/game/vehicle.hpp"
|
||||||
"src/game/vehicle.cpp"
|
"src/game/vehicle.cpp"
|
||||||
"src/game/world.hpp"
|
"src/game/world.hpp"
|
||||||
|
|||||||
@ -9,12 +9,12 @@ void assets::LoadCMDStream(std::istream& is, CmdCallback handler)
|
|||||||
|
|
||||||
while (std::getline(is, line))
|
while (std::getline(is, line))
|
||||||
{
|
{
|
||||||
|
// skip whitespace
|
||||||
|
line.erase(0, line.find_first_not_of(" \t\r\n"));
|
||||||
|
|
||||||
if (line.empty() || line[0] == '#') // Skip empty lines and comments
|
if (line.empty() || line[0] == '#') // Skip empty lines and comments
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// skip whitespace
|
|
||||||
line.erase(0, line.find_first_not_of(" \t"));
|
|
||||||
|
|
||||||
std::istringstream iss(line);
|
std::istringstream iss(line);
|
||||||
iss >> command;
|
iss >> command;
|
||||||
|
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
#include "vehicle_tuning_list.hpp"
|
|
||||||
|
|
||||||
#include "cmdfile.hpp"
|
|
||||||
|
|
||||||
std::unique_ptr<const assets::VehicleTuningList> assets::VehicleTuningList::LoadFromFile(const std::string& filename)
|
|
||||||
{
|
|
||||||
auto tuninglist = std::make_unique<VehicleTuningList>();
|
|
||||||
|
|
||||||
if (!fs::FileExists(filename))
|
|
||||||
return tuninglist; // empty
|
|
||||||
|
|
||||||
LoadCMDFile(filename, [&](const std::string& command, std::istringstream& iss) {
|
|
||||||
if (command == "wheel")
|
|
||||||
{
|
|
||||||
VehicleWheelPreset wheel{};
|
|
||||||
wheel.displayname = ParseString(iss);
|
|
||||||
iss >> wheel.price >> wheel.model;
|
|
||||||
|
|
||||||
tuninglist->wheels.emplace_back(wheel);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return tuninglist;
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace assets
|
|
||||||
{
|
|
||||||
|
|
||||||
struct VehicleWheelPreset
|
|
||||||
{
|
|
||||||
uint32_t price;
|
|
||||||
std::string displayname;
|
|
||||||
std::string model;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VehicleTuningList
|
|
||||||
{
|
|
||||||
std::vector<VehicleWheelPreset> wheels;
|
|
||||||
|
|
||||||
static std::unique_ptr<const VehicleTuningList> LoadFromFile(const std::string& filename);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -48,9 +48,6 @@ std::shared_ptr<const assets::VehicleModel> assets::VehicleModel::LoadFromFile(c
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// tuning list
|
|
||||||
veh->tuninglist_ = VehicleTuningList::LoadFromFile(filename + ".tun");
|
|
||||||
|
|
||||||
return veh;
|
return veh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "model.hpp"
|
#include "model.hpp"
|
||||||
#include "utils/transform.hpp"
|
#include "utils/transform.hpp"
|
||||||
#include "vehicle_tuning_list.hpp"
|
|
||||||
|
|
||||||
namespace assets
|
namespace assets
|
||||||
{
|
{
|
||||||
@ -36,13 +35,11 @@ public:
|
|||||||
const std::shared_ptr<const Model>& GetModel() const { return basemodel_; }
|
const std::shared_ptr<const Model>& GetModel() const { return basemodel_; }
|
||||||
const std::vector<VehicleWheel>& GetWheels() const { return wheels_; }
|
const std::vector<VehicleWheel>& GetWheels() const { return wheels_; }
|
||||||
const Transform* GetLocation(const std::string& name) const;
|
const Transform* GetLocation(const std::string& name) const;
|
||||||
const VehicleTuningList& GetTuningList() const { return *tuninglist_; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<const Model> basemodel_;
|
std::shared_ptr<const Model> basemodel_;
|
||||||
std::vector<VehicleWheel> wheels_;
|
std::vector<VehicleWheel> wheels_;
|
||||||
std::map<std::string, Transform> locations_;
|
std::map<std::string, Transform> locations_;
|
||||||
std::unique_ptr<const VehicleTuningList> tuninglist_;
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,9 +5,13 @@
|
|||||||
game::DrivableVehicle::DrivableVehicle(World& world, const VehicleTuning& tuning) : Vehicle(world, tuning), Usable(GetRoot().matrix)
|
game::DrivableVehicle::DrivableVehicle(World& world, const VehicleTuning& tuning) : Vehicle(world, tuning), Usable(GetRoot().matrix)
|
||||||
{
|
{
|
||||||
InitSeats();
|
InitSeats();
|
||||||
|
OnPhysicsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::DrivableVehicle::OnPhysicsChanged()
|
||||||
|
{
|
||||||
// make body usable
|
// make body usable
|
||||||
collision::AddObjectFlags(&GetBtBody(), collision::OF_USABLE);
|
collision::AddObjectFlags(&GetPhysics()->GetBtBody(), collision::OF_USABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool game::DrivableVehicle::QueryUseTarget(PlayerCharacter& character, uint32_t target_id, UseTargetQueryResult& res)
|
bool game::DrivableVehicle::QueryUseTarget(PlayerCharacter& character, uint32_t target_id, UseTargetQueryResult& res)
|
||||||
@ -90,7 +94,7 @@ static std::string GetColorTextPrefix(uint32_t color)
|
|||||||
|
|
||||||
void game::DrivableVehicle::InitSeats()
|
void game::DrivableVehicle::InitSeats()
|
||||||
{
|
{
|
||||||
uint32_t color = GetTuning().primary_color;
|
uint32_t color = GetTuningResult().colors[0];
|
||||||
std::string prefix = "vlízt do " + GetColorTextPrefix(color) + GetModelName() + "^r";
|
std::string prefix = "vlízt do " + GetColorTextPrefix(color) + GetModelName() + "^r";
|
||||||
|
|
||||||
const auto& veh = *GetModel();
|
const auto& veh = *GetModel();
|
||||||
|
|||||||
@ -20,6 +20,8 @@ public:
|
|||||||
|
|
||||||
DrivableVehicle(World& world, const VehicleTuning& tuning);
|
DrivableVehicle(World& world, const VehicleTuning& tuning);
|
||||||
|
|
||||||
|
virtual void OnPhysicsChanged() override;
|
||||||
|
|
||||||
virtual bool QueryUseTarget(PlayerCharacter& character, uint32_t target_id, UseTargetQueryResult& res) override;
|
virtual bool QueryUseTarget(PlayerCharacter& character, uint32_t target_id, UseTargetQueryResult& res) override;
|
||||||
virtual void Use(PlayerCharacter& character, uint32_t target_id) override;
|
virtual void Use(PlayerCharacter& character, uint32_t target_id) override;
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ void game::NpcCharacter::VehicleChanged()
|
|||||||
{
|
{
|
||||||
roads_ = world_.GetMap().GetGraph("roads");
|
roads_ = world_.GetMap().GetGraph("roads");
|
||||||
|
|
||||||
seg_start_ = GetVehicle()->GetPosition();
|
seg_start_ = GetVehicle()->GetRootTransform().position;
|
||||||
|
|
||||||
size_t start_node = 0;
|
size_t start_node = 0;
|
||||||
float min_dist = std::numeric_limits<float>().infinity();
|
float min_dist = std::numeric_limits<float>().infinity();
|
||||||
@ -87,8 +87,10 @@ void game::NpcCharacter::VehicleThink()
|
|||||||
if (!IsDriver() || !GetVehicle() || !roads_)
|
if (!IsDriver() || !GetVehicle() || !roads_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
glm::vec3 pos = GetVehicle()->GetPosition();
|
const auto& vehicle_trans = GetVehicle()->GetRootTransform();
|
||||||
glm::quat rot = GetVehicle()->GetRotation();
|
|
||||||
|
const glm::vec3& pos = vehicle_trans.position;
|
||||||
|
const glm::quat& rot = vehicle_trans.rotation;
|
||||||
glm::vec3 forward = rot * glm::vec3{0.0f, 1.0f, 0.0f};
|
glm::vec3 forward = rot * glm::vec3{0.0f, 1.0f, 0.0f};
|
||||||
|
|
||||||
// glm::vec3 target = s->roads.nodes[s->node].position;
|
// glm::vec3 target = s->roads.nodes[s->node].position;
|
||||||
|
|||||||
@ -56,9 +56,10 @@ game::OpenWorld::OpenWorld() : EnterableWorld("openworld")
|
|||||||
// initial twingo
|
// initial twingo
|
||||||
VehicleTuning twingo_tuning;
|
VehicleTuning twingo_tuning;
|
||||||
twingo_tuning.model = "twingo";
|
twingo_tuning.model = "twingo";
|
||||||
twingo_tuning.primary_color = 0x0077FF;
|
twingo_tuning.parts["primarycolor"] = "orange";
|
||||||
twingo_tuning.wheels_idx = 1; // enkei
|
// twingo_tuning.primary_color = 0x0077FF;
|
||||||
twingo_tuning.wheel_color = 0x00FF00;
|
// twingo_tuning.wheels_idx = 1; // enkei
|
||||||
|
// twingo_tuning.wheel_color = 0x00FF00;
|
||||||
|
|
||||||
auto& veh = Spawn<game::DrivableVehicle>(twingo_tuning);
|
auto& veh = Spawn<game::DrivableVehicle>(twingo_tuning);
|
||||||
veh.SetPosition({110.0f, 100.0f, 5.0f});
|
veh.SetPosition({110.0f, 100.0f, 5.0f});
|
||||||
@ -83,11 +84,23 @@ game::DrivableVehicle& game::OpenWorld::SpawnRandomVehicle()
|
|||||||
{
|
{
|
||||||
game::VehicleTuning tuning;
|
game::VehicleTuning tuning;
|
||||||
tuning.model = GetRandomCarModel();
|
tuning.model = GetRandomCarModel();
|
||||||
tuning.primary_color = GetRandomColor24();
|
// tuning.primary_color = GetRandomColor24();
|
||||||
|
|
||||||
auto& vehicle = Spawn<game::DrivableVehicle>(tuning);
|
auto& vehicle = Spawn<game::DrivableVehicle>(tuning);
|
||||||
// vehicle.SetNametag("bot (" + std::to_string(vehicle.GetEntNum()) + ")");
|
// vehicle.SetNametag("bot (" + std::to_string(vehicle.GetEntNum()) + ")");
|
||||||
|
|
||||||
|
auto& tuning_list = vehicle.GetTuningList();
|
||||||
|
auto& colors = tuning_list->groups[0].parts;
|
||||||
|
|
||||||
|
size_t random_color = rand() % colors.size();
|
||||||
|
|
||||||
|
auto item = colors.begin();
|
||||||
|
std::advance( item, random_color);
|
||||||
|
|
||||||
|
tuning.parts["primarycolor"] = item->second.id;
|
||||||
|
|
||||||
|
vehicle.SetTuning(tuning);
|
||||||
|
|
||||||
return vehicle;
|
return vehicle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#include "tuning_world.hpp"
|
#include "tuning_world.hpp"
|
||||||
#include "player_character.hpp"
|
#include "player_character.hpp"
|
||||||
#include "utils/colors.hpp"
|
#include "utils/colors.hpp"
|
||||||
#include "assets/vehicle_tuning_list.hpp"
|
|
||||||
#include "game.hpp"
|
#include "game.hpp"
|
||||||
|
|
||||||
game::TuningWorld::TuningWorld(Game& game, EnterableWorld& exit_world, const glm::vec3& exit_pos, float exit_yaw, std::string mapname) :
|
game::TuningWorld::TuningWorld(Game& game, EnterableWorld& exit_world, const glm::vec3& exit_pos, float exit_yaw, std::string mapname) :
|
||||||
@ -32,7 +31,7 @@ void game::TuningWorld::OnVehicleJoined(DrivableVehicle& vehicle)
|
|||||||
throw std::runtime_error("vehicle joined to tuning without ACTIVE player driver??");
|
throw std::runtime_error("vehicle joined to tuning without ACTIVE player driver??");
|
||||||
|
|
||||||
vehicle_ = &vehicle;
|
vehicle_ = &vehicle;
|
||||||
tuning_list_ = &vehicle.GetModel()->GetTuningList();
|
tuning_list_ = vehicle.GetTuningList().get();
|
||||||
player_ = player;
|
player_ = player;
|
||||||
|
|
||||||
Setup();
|
Setup();
|
||||||
@ -54,73 +53,133 @@ const std::string& game::TuningWorld::GetOccupantName() const
|
|||||||
void game::TuningWorld::Setup()
|
void game::TuningWorld::Setup()
|
||||||
{
|
{
|
||||||
tuning_ = vehicle_->GetTuning();
|
tuning_ = vehicle_->GetTuning();
|
||||||
UpdateTuningVals();
|
// UpdateTuningVals();
|
||||||
DisplayTuningMenu();
|
DisplayTuningMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
void game::TuningWorld::UpdateTuningVals()
|
// 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::AddTuningGroupSelect(game::RemoteMenu& menu, const VehicleTuningGroup& group)
|
||||||
{
|
{
|
||||||
tun_primary_color_ = ColorU32ToU8Vec3(tuning_.primary_color);
|
size_t num_parts = group.parts.size();
|
||||||
|
if (num_parts == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
tun_wheel_idx_ = tuning_.wheels_idx;
|
struct SliderState
|
||||||
tun_wheel_color_ = ColorU32ToU8Vec3(tuning_.wheel_color);
|
|
||||||
}
|
|
||||||
|
|
||||||
void game::TuningWorld::UpdateTuning()
|
|
||||||
{
|
{
|
||||||
tuning_.primary_color = ColorU8Vec3ToU32(tun_primary_color_);
|
const VehicleTuningGroup* group;
|
||||||
|
int idx = 0;
|
||||||
tuning_.wheels_idx = tun_wheel_idx_;
|
std::vector<std::string> ids;
|
||||||
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);
|
std::string current_part;
|
||||||
slider.SetOnSelect(on_select);
|
|
||||||
|
auto current_it = tuning_.parts.find(group.id);
|
||||||
|
if (current_it != tuning_.parts.end())
|
||||||
|
{
|
||||||
|
current_part = current_it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AddColorSliders(game::RemoteMenu& menu, glm::u8vec3& color, std::string name, std::function<void()> on_change)
|
auto state = std::make_shared<SliderState>();
|
||||||
|
state->group = &group;
|
||||||
|
|
||||||
|
state->ids.reserve(num_parts);
|
||||||
|
size_t i = 0;
|
||||||
|
for (const auto& part : group.parts)
|
||||||
{
|
{
|
||||||
AddColorChannelSlider(menu, color.r, name + " ^f00R", on_change);
|
state->ids.push_back(part.first);
|
||||||
AddColorChannelSlider(menu, color.g, name + " ^0f0G", on_change);
|
|
||||||
AddColorChannelSlider(menu, color.b, name + " ^00fB", on_change);
|
if (part.first == current_part)
|
||||||
|
state->idx = i;
|
||||||
|
|
||||||
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
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, group.displayname);
|
||||||
{
|
|
||||||
auto& slider = menu.AddItem(game::RM_SELECT, "kola");
|
|
||||||
|
|
||||||
auto on_select = [&slider, &idx, &tuning_list, on_change = std::move(on_change)] (int dir) {
|
auto on_select = [&slider, this, state](int dir) mutable {
|
||||||
auto& wheels = tuning_list.wheels;
|
if (dir < 0 && state->idx == 0)
|
||||||
|
state->idx = state->ids.size() - 1;
|
||||||
|
else if (dir > 0 && (state->idx + 1) >= state->ids.size())
|
||||||
|
state->idx = 0;
|
||||||
|
else
|
||||||
|
state->idx += dir;
|
||||||
|
|
||||||
if (dir < 0 && idx == 0)
|
auto& part_id = state->ids[state->idx];
|
||||||
return;
|
tuning_.parts[state->group->id] = part_id;
|
||||||
|
slider.SetSelection(state->group->parts.at(part_id).displayname);
|
||||||
|
|
||||||
if (dir > 0 && (idx + 1) >= wheels.size())
|
if (dir != 0)
|
||||||
return;
|
vehicle_->SetTuning(tuning_);
|
||||||
|
|
||||||
idx += dir;
|
|
||||||
|
|
||||||
slider.SetSelection(tuning_list.wheels[idx].displayname);
|
|
||||||
on_change();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
on_select(0);
|
on_select(0);
|
||||||
@ -133,14 +192,19 @@ void game::TuningWorld::DisplayTuningMenu()
|
|||||||
auto& menu = player_->DisplayMenu("tuning");
|
auto& menu = player_->DisplayMenu("tuning");
|
||||||
menu_ = &menu;
|
menu_ = &menu;
|
||||||
|
|
||||||
auto on_change = [this] { UpdateTuning(); };
|
// auto on_change = [this] { UpdateTuning(); };
|
||||||
|
|
||||||
AddColorSliders(menu, tun_primary_color_, "primární", on_change);
|
// AddColorSliders(menu, tun_primary_color_, "primární", on_change);
|
||||||
|
|
||||||
if (!tuning_list_->wheels.empty())
|
// if (!tuning_list_->wheels.empty())
|
||||||
|
// {
|
||||||
|
// AddWheelTypeSlider(menu, *tuning_list_, tun_wheel_idx_, on_change);
|
||||||
|
// AddColorSliders(menu, tun_wheel_color_, "kola", on_change);
|
||||||
|
// }
|
||||||
|
|
||||||
|
for (const auto& group : tuning_list_->groups)
|
||||||
{
|
{
|
||||||
AddWheelTypeSlider(menu, *tuning_list_, tun_wheel_idx_, on_change);
|
AddTuningGroupSelect(menu, group);
|
||||||
AddColorSliders(menu, tun_wheel_color_, "kola", on_change);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& exit_btn = menu.AddItem(RM_BUTTON, "vylézt");
|
auto& exit_btn = menu.AddItem(RM_BUTTON, "vylézt");
|
||||||
|
|||||||
@ -26,9 +26,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
void Setup();
|
void Setup();
|
||||||
|
|
||||||
void UpdateTuningVals();
|
void AddTuningGroupSelect(game::RemoteMenu& menu, const VehicleTuningGroup& group);
|
||||||
void UpdateTuning();
|
|
||||||
|
|
||||||
void DisplayTuningMenu();
|
void DisplayTuningMenu();
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
@ -42,17 +40,13 @@ private:
|
|||||||
// active player
|
// active player
|
||||||
Player* player_ = nullptr;
|
Player* player_ = nullptr;
|
||||||
DrivableVehicle* vehicle_ = nullptr;
|
DrivableVehicle* vehicle_ = nullptr;
|
||||||
const assets::VehicleTuningList* tuning_list_ = nullptr;
|
const VehicleTuningList* tuning_list_ = nullptr;
|
||||||
|
|
||||||
game::RemoteMenu* menu_ = nullptr;
|
game::RemoteMenu* menu_ = nullptr;
|
||||||
|
|
||||||
VehicleTuning tuning_;
|
VehicleTuning tuning_;
|
||||||
|
|
||||||
|
|
||||||
glm::u8vec3 tun_primary_color_;
|
|
||||||
size_t tun_wheel_idx_;
|
|
||||||
glm::u8vec3 tun_wheel_color_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -15,87 +15,13 @@ static std::shared_ptr<const assets::VehicleModel> LoadVehicleModelByName(const
|
|||||||
|
|
||||||
game::Vehicle::Vehicle(World& world, const VehicleTuning& tuning)
|
game::Vehicle::Vehicle(World& world, const VehicleTuning& tuning)
|
||||||
: Entity(world, net::ET_VEHICLE), tuning_(tuning), model_(LoadVehicleModelByName(tuning.model)),
|
: Entity(world, net::ET_VEHICLE), tuning_(tuning), model_(LoadVehicleModelByName(tuning.model)),
|
||||||
motion_(root_.local)
|
tuninglist_(VehicleTuningList::LoadFromFile("data/" + tuning.model + ".tun"))
|
||||||
{
|
{
|
||||||
root_.local.position.z = 10.0f;
|
root_.local.position.z = 10.0f;
|
||||||
|
|
||||||
// setup chassis rigidbody
|
wheels_.resize(model_->GetWheels().size());
|
||||||
float mass = 1000.0f;
|
|
||||||
|
|
||||||
btCollisionShape* shape = model_->GetModel()->GetColShape();
|
ApplyTuning(tuning);
|
||||||
if (!shape)
|
|
||||||
throw std::runtime_error("Making vehicle with no shape");
|
|
||||||
|
|
||||||
btVector3 local_inertia(0, 0, 0);
|
|
||||||
shape->calculateLocalInertia(mass, local_inertia);
|
|
||||||
|
|
||||||
btRigidBody::btRigidBodyConstructionInfo rb_info(mass, &motion_, shape, local_inertia);
|
|
||||||
body_ = std::make_unique<btRigidBody>(rb_info);
|
|
||||||
// body_->setActivationState(DISABLE_DEACTIVATION);
|
|
||||||
|
|
||||||
collision::SetObjectInfo(body_.get(), collision::OT_ENTITY, collision::OF_NOTIFY_CONTACT, this);
|
|
||||||
|
|
||||||
// setup vehicle
|
|
||||||
btRaycastVehicle::btVehicleTuning bt_tuning;
|
|
||||||
vehicle_ = std::make_unique<collision::RaycastVehicle>(bt_tuning, body_.get(), &world_.GetVehicleRaycaster());
|
|
||||||
vehicle_->setCoordinateSystem(0, 2, 1);
|
|
||||||
|
|
||||||
// setup wheels
|
|
||||||
// btVector3 wheelDirectionCS0(0, -1, 0);
|
|
||||||
// btVector3 wheelAxleCS(-1, 0, 0);
|
|
||||||
btVector3 wheelDirectionCS0(0, 0, -1);
|
|
||||||
btVector3 wheelAxleCS(1, 0, 0);
|
|
||||||
|
|
||||||
wheel_z_offset_ = 0.2f;
|
|
||||||
|
|
||||||
const auto& wheels = model_->GetWheels();
|
|
||||||
|
|
||||||
if (wheels.size() > MAX_WHEELS)
|
|
||||||
throw std::runtime_error("Max wheels exceeded");
|
|
||||||
|
|
||||||
num_wheels_ = wheels.size();
|
|
||||||
|
|
||||||
for (const auto& wheeldef : wheels)
|
|
||||||
{
|
|
||||||
float wheelRadius = wheeldef.radius;
|
|
||||||
|
|
||||||
float friction = 2.2f; // 5.0f;
|
|
||||||
float suspensionStiffness = 50.0f;
|
|
||||||
// float suspensionDamping = 2.3f;
|
|
||||||
// float suspensionCompression = 4.4f;
|
|
||||||
float suspensionRestLength = 0.3f;
|
|
||||||
float rollInfluence = 0.3f;
|
|
||||||
|
|
||||||
float maxSuspensionForce = 90000.0f;
|
|
||||||
float maxSuspensionTravelCm = 15.0f;
|
|
||||||
|
|
||||||
float k = 0.2f;
|
|
||||||
|
|
||||||
const bool is_front = !(wheeldef.type & assets::WHEEL_REAR);
|
|
||||||
|
|
||||||
if (!is_front)
|
|
||||||
friction *= 1.5f;
|
|
||||||
|
|
||||||
btVector3 wheel_pos(wheeldef.position.x, wheeldef.position.y, wheeldef.position.z + wheel_z_offset_);
|
|
||||||
auto& wi = vehicle_->addWheel(wheel_pos, wheelDirectionCS0, wheelAxleCS, suspensionRestLength, wheelRadius,
|
|
||||||
bt_tuning, is_front);
|
|
||||||
|
|
||||||
wi.m_suspensionStiffness = suspensionStiffness;
|
|
||||||
|
|
||||||
wi.m_wheelsDampingCompression = k * 2.0 * btSqrt(suspensionStiffness); // vehicleTuning.suspensionCompression;
|
|
||||||
wi.m_wheelsDampingRelaxation = k * 3.3 * btSqrt(suspensionStiffness); // vehicleTuning.suspensionDamping;
|
|
||||||
|
|
||||||
wi.m_frictionSlip = friction;
|
|
||||||
// if (wi.m_bIsFrontWheel) wi.m_frictionSlip = vehicleTuning.friction * 1.4f;
|
|
||||||
|
|
||||||
wi.m_rollInfluence = rollInfluence;
|
|
||||||
wi.m_maxSuspensionForce = maxSuspensionForce;
|
|
||||||
wi.m_maxSuspensionTravelCm = maxSuspensionTravelCm;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& bt_world = world_.GetBtWorld();
|
|
||||||
bt_world.addRigidBody(body_.get(), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::AllFilter);
|
|
||||||
bt_world.addAction(vehicle_.get());
|
|
||||||
|
|
||||||
// init deform
|
// init deform
|
||||||
gfx::DeformGridInfo info{};
|
gfx::DeformGridInfo info{};
|
||||||
@ -163,7 +89,6 @@ void game::Vehicle::OnContact(const collision::ContactInfo& info)
|
|||||||
{
|
{
|
||||||
Deform(info.pos, -glm::normalize(info.normal) * 0.1f, 1.0f);
|
Deform(info.pos, -glm::normalize(info.normal) * 0.1f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void game::Vehicle::SetInput(VehicleInputType type, bool enable)
|
void game::Vehicle::SetInput(VehicleInputType type, bool enable)
|
||||||
@ -174,28 +99,18 @@ void game::Vehicle::SetInput(VehicleInputType type, bool enable)
|
|||||||
in_ &= ~(1 << type);
|
in_ &= ~(1 << type);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 game::Vehicle::GetPosition() const
|
|
||||||
{
|
|
||||||
btVector3 pos = body_->getWorldTransform().getOrigin();
|
|
||||||
return glm::vec3(pos.x(), pos.y(), pos.z());
|
|
||||||
}
|
|
||||||
|
|
||||||
void game::Vehicle::SetPosition(const glm::vec3& pos)
|
void game::Vehicle::SetPosition(const glm::vec3& pos)
|
||||||
{
|
{
|
||||||
auto t = body_->getWorldTransform();
|
auto& body = physics_->GetBtBody();
|
||||||
t.setOrigin(btVector3(pos.x, pos.y, pos.z));
|
|
||||||
body_->setWorldTransform(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::quat game::Vehicle::GetRotation() const
|
auto t = body.getWorldTransform();
|
||||||
{
|
t.setOrigin(btVector3(pos.x, pos.y, pos.z));
|
||||||
btQuaternion rot = body_->getWorldTransform().getRotation();
|
body.setWorldTransform(t);
|
||||||
return glm::quat(rot.w(), rot.x(), rot.y(), rot.z());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float game::Vehicle::GetSpeed() const
|
float game::Vehicle::GetSpeed() const
|
||||||
{
|
{
|
||||||
return vehicle_->getCurrentSpeedKmHour();
|
return physics_->GetBtVehicle().getCurrentSpeedKmHour();
|
||||||
}
|
}
|
||||||
|
|
||||||
void game::Vehicle::SetSteering(bool analog, float value)
|
void game::Vehicle::SetSteering(bool analog, float value)
|
||||||
@ -206,29 +121,24 @@ void game::Vehicle::SetSteering(bool analog, float value)
|
|||||||
|
|
||||||
void game::Vehicle::SetTuning(const VehicleTuning& tuning)
|
void game::Vehicle::SetTuning(const VehicleTuning& tuning)
|
||||||
{
|
{
|
||||||
tuning_ = tuning;
|
ApplyTuning(tuning);
|
||||||
|
|
||||||
|
// send to clients
|
||||||
auto msg = BeginEntMsg(net::EMSG_TUNING);
|
auto msg = BeginEntMsg(net::EMSG_TUNING);
|
||||||
WriteTuning(msg);
|
WriteTuning(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
game::Vehicle::~Vehicle()
|
|
||||||
{
|
|
||||||
auto& bt_world = world_.GetBtWorld();
|
|
||||||
bt_world.removeRigidBody(body_.get());
|
|
||||||
bt_world.removeAction(vehicle_.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void game::Vehicle::ProcessInput()
|
void game::Vehicle::ProcessInput()
|
||||||
{
|
{
|
||||||
// TODO: totally fix
|
// TODO: totally fix
|
||||||
|
|
||||||
// std::string nt = "";
|
// std::string nt = "";
|
||||||
|
|
||||||
if (in_) {
|
if (in_)
|
||||||
|
{
|
||||||
// nt += "in ";
|
// nt += "in ";
|
||||||
// body_->setActivationState(ACTIVE_TAG);
|
// body_->setActivationState(ACTIVE_TAG);
|
||||||
body_->activate();
|
physics_->GetBtBody().activate();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -243,17 +153,16 @@ void game::Vehicle::ProcessInput()
|
|||||||
// float steeringIncrement = .04 * 60;
|
// float steeringIncrement = .04 * 60;
|
||||||
// float steeringClamp = .5;
|
// float steeringClamp = .5;
|
||||||
// float maxEngineForce = 7000;
|
// float maxEngineForce = 7000;
|
||||||
float maxEngineForce = 3200;
|
float maxEngineForce = tuning_ctx_.engine_force;
|
||||||
float maxBreakingForce = 400;
|
float maxBreakingForce = tuning_ctx_.braking_force;
|
||||||
|
|
||||||
float speed = vehicle_->getCurrentSpeedKmHour();
|
float speed = GetSpeed();
|
||||||
if (glm::abs(speed) > 200.0f)
|
if (glm::abs(speed) > 200.0f)
|
||||||
maxEngineForce = 100.0f;
|
maxEngineForce = 100.0f;
|
||||||
|
|
||||||
float engineForce = 0;
|
float engineForce = 0;
|
||||||
float breakingForce = 0;
|
float breakingForce = 0;
|
||||||
|
|
||||||
|
|
||||||
float maxsc = .5f;
|
float maxsc = .5f;
|
||||||
float minsc = .08f;
|
float minsc = .08f;
|
||||||
float sl = 130.f;
|
float sl = 130.f;
|
||||||
@ -263,7 +172,6 @@ void game::Vehicle::ProcessInput()
|
|||||||
float steeringSpeed = steeringClamp * 5.0f;
|
float steeringSpeed = steeringClamp * 5.0f;
|
||||||
float steeringInc = steeringSpeed * t_delta;
|
float steeringInc = steeringSpeed * t_delta;
|
||||||
|
|
||||||
|
|
||||||
const bool in_forward = in_ & (1 << VIN_FORWARD);
|
const bool in_forward = in_ & (1 << VIN_FORWARD);
|
||||||
const bool in_backward = in_ & (1 << VIN_BACKWARD);
|
const bool in_backward = in_ & (1 << VIN_BACKWARD);
|
||||||
const bool in_left = in_ & (1 << VIN_LEFT);
|
const bool in_left = in_ & (1 << VIN_LEFT);
|
||||||
@ -287,7 +195,7 @@ void game::Vehicle::ProcessInput()
|
|||||||
// idle breaking
|
// idle breaking
|
||||||
if (!in_forward && !in_backward)
|
if (!in_forward && !in_backward)
|
||||||
{
|
{
|
||||||
breakingForce = maxBreakingForce * 0.05f;
|
breakingForce = 20.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!steering_analog_)
|
if (!steering_analog_)
|
||||||
@ -341,16 +249,29 @@ void game::Vehicle::ProcessInput()
|
|||||||
steering_ = -steeringClamp;
|
steering_ = -steeringClamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
vehicle_->applyEngineForce(engineForce, 0);
|
auto& vehicle = physics_->GetBtVehicle();
|
||||||
vehicle_->applyEngineForce(engineForce, 1);
|
|
||||||
|
|
||||||
vehicle_->setBrake(breakingForce * 0.1f, 0);
|
for (size_t i = 0; i < wheels_.size(); ++i)
|
||||||
vehicle_->setBrake(breakingForce * 0.1f, 1);
|
{
|
||||||
vehicle_->setBrake(breakingForce, 2);
|
float engine_factor = tuning_ctx_.wheels[i].engine_factor;
|
||||||
vehicle_->setBrake(breakingForce, 3);
|
if (engine_factor > 0.0001f)
|
||||||
|
{
|
||||||
|
vehicle.applyEngineForce(engine_factor * engineForce, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
float braking_factor = tuning_ctx_.wheels[i].braking_factor;
|
||||||
|
if (braking_factor > 0.0001f)
|
||||||
|
{
|
||||||
|
vehicle.setBrake(braking_factor * breakingForce, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
float steering_factor = tuning_ctx_.wheels[i].steering_factor;
|
||||||
|
if (std::abs(steering_factor) > 0.0001f)
|
||||||
|
{
|
||||||
|
vehicle.setSteeringValue(steering_factor * steering_, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vehicle_->setSteeringValue(steering_, 0);
|
|
||||||
vehicle_->setSteeringValue(steering_, 1);
|
|
||||||
|
|
||||||
if (glm::abs(engineForce) > 0)
|
if (glm::abs(engineForce) > 0)
|
||||||
flags_ |= VF_ACCELERATING;
|
flags_ |= VF_ACCELERATING;
|
||||||
@ -394,7 +315,6 @@ void game::Vehicle::UpdateCrash()
|
|||||||
PlaySound("crash", volume, pitch);
|
PlaySound("crash", volume, pitch);
|
||||||
no_crash_frames_ = 7 + rand() % 10;
|
no_crash_frames_ = 7 + rand() % 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crash_intensity_ = 0.0f;
|
crash_intensity_ = 0.0f;
|
||||||
@ -402,12 +322,14 @@ void game::Vehicle::UpdateCrash()
|
|||||||
|
|
||||||
void game::Vehicle::UpdateWheels()
|
void game::Vehicle::UpdateWheels()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < num_wheels_; ++i)
|
auto& vehicle = physics_->GetBtVehicle();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < wheels_.size(); ++i)
|
||||||
{
|
{
|
||||||
auto& bt_wheel = vehicle_->getWheelInfo(i);
|
auto& bt_wheel = vehicle.getWheelInfo(i);
|
||||||
wheels_[i].speed = -(bt_wheel.m_rotation - wheels_[i].rotation) * 25.0f;
|
wheels_[i].speed = -(bt_wheel.m_rotation - wheels_[i].rotation) * 25.0f;
|
||||||
wheels_[i].rotation = bt_wheel.m_rotation;
|
wheels_[i].rotation = bt_wheel.m_rotation;
|
||||||
wheels_[i].z_offset = wheel_z_offset_ - bt_wheel.m_raycastInfo.m_suspensionLength;
|
wheels_[i].z_offset = tuning_ctx_.wheels[i].z_offset - bt_wheel.m_raycastInfo.m_suspensionLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,7 +344,7 @@ void game::Vehicle::UpdateSyncState()
|
|||||||
|
|
||||||
state.steering.Encode(steering_);
|
state.steering.Encode(steering_);
|
||||||
|
|
||||||
for (size_t i = 0; i < num_wheels_; ++i)
|
for (size_t i = 0; i < wheels_.size(); ++i)
|
||||||
{
|
{
|
||||||
auto& wheel = wheels_[i];
|
auto& wheel = wheels_[i];
|
||||||
state.wheels[i].z_offset.Encode(wheel.z_offset);
|
state.wheels[i].z_offset.Encode(wheel.z_offset);
|
||||||
@ -441,8 +363,7 @@ game::VehicleSyncFieldFlags game::Vehicle::WriteState(net::OutMessage& msg, cons
|
|||||||
msg.Write(curr.flags);
|
msg.Write(curr.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curr.pos.x.value != base.pos.x.value ||
|
if (curr.pos.x.value != base.pos.x.value || curr.pos.y.value != base.pos.y.value ||
|
||||||
curr.pos.y.value != base.pos.y.value ||
|
|
||||||
curr.pos.z.value != base.pos.z.value)
|
curr.pos.z.value != base.pos.z.value)
|
||||||
{
|
{
|
||||||
fields |= VSF_POSITION;
|
fields |= VSF_POSITION;
|
||||||
@ -452,8 +373,7 @@ game::VehicleSyncFieldFlags game::Vehicle::WriteState(net::OutMessage& msg, cons
|
|||||||
net::WriteDelta(msg, curr.pos.z, base.pos.z);
|
net::WriteDelta(msg, curr.pos.z, base.pos.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curr.rot.x.value != base.rot.x.value ||
|
if (curr.rot.x.value != base.rot.x.value || curr.rot.y.value != base.rot.y.value ||
|
||||||
curr.rot.y.value != base.rot.y.value ||
|
|
||||||
curr.rot.z.value != base.rot.z.value)
|
curr.rot.z.value != base.rot.z.value)
|
||||||
{
|
{
|
||||||
fields |= VSF_ROTATION;
|
fields |= VSF_ROTATION;
|
||||||
@ -471,7 +391,7 @@ game::VehicleSyncFieldFlags game::Vehicle::WriteState(net::OutMessage& msg, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool wheels_changed = false;
|
bool wheels_changed = false;
|
||||||
for (size_t i = 0; i < num_wheels_; ++i)
|
for (size_t i = 0; i < wheels_.size(); ++i)
|
||||||
{
|
{
|
||||||
if (curr.wheels[i].z_offset.value != base.wheels[i].z_offset.value ||
|
if (curr.wheels[i].z_offset.value != base.wheels[i].z_offset.value ||
|
||||||
curr.wheels[i].speed.value != base.wheels[i].speed.value)
|
curr.wheels[i].speed.value != base.wheels[i].speed.value)
|
||||||
@ -485,7 +405,7 @@ game::VehicleSyncFieldFlags game::Vehicle::WriteState(net::OutMessage& msg, cons
|
|||||||
{
|
{
|
||||||
fields |= VSF_WHEELS;
|
fields |= VSF_WHEELS;
|
||||||
|
|
||||||
for (size_t i = 0; i < num_wheels_; ++i)
|
for (size_t i = 0; i < wheels_.size(); ++i)
|
||||||
{
|
{
|
||||||
net::WriteDelta(msg, curr.wheels[i].z_offset, base.wheels[i].z_offset);
|
net::WriteDelta(msg, curr.wheels[i].z_offset, base.wheels[i].z_offset);
|
||||||
net::WriteDelta(msg, curr.wheels[i].speed, base.wheels[i].speed);
|
net::WriteDelta(msg, curr.wheels[i].speed, base.wheels[i].speed);
|
||||||
@ -563,11 +483,147 @@ void game::Vehicle::SendDeformMsg(const net::PositionQ& pos, const net::Position
|
|||||||
net::WritePositionQ(msg, deform);
|
net::WritePositionQ(msg, deform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void game::Vehicle::ApplyTuning(const VehicleTuning& tuning)
|
||||||
|
{
|
||||||
|
tuning_ = tuning;
|
||||||
|
|
||||||
|
tuning_ctx_ = VehicleTuningContext{};
|
||||||
|
|
||||||
|
// setup wheels
|
||||||
|
const auto& model_wheels = model_->GetWheels();
|
||||||
|
tuning_ctx_.wheels.resize(model_wheels.size());
|
||||||
|
for (size_t i = 0; i < model_wheels.size(); ++i)
|
||||||
|
{
|
||||||
|
tuning_ctx_.wheels[i].front = !(model_wheels[i].type & assets::WHEEL_REAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply tunning to ctx
|
||||||
|
for (const auto& func : tuninglist_->default_funcs)
|
||||||
|
{
|
||||||
|
func(tuning_ctx_);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& group : tuninglist_->groups)
|
||||||
|
{
|
||||||
|
auto group_it = tuning_.parts.find(group.id);
|
||||||
|
if (group_it == tuning_.parts.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto& part_name = group_it->second;
|
||||||
|
const auto& part = group.parts.at(part_name);
|
||||||
|
|
||||||
|
for (const auto& func : part.funcs)
|
||||||
|
{
|
||||||
|
func(tuning_ctx_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (re)create physics
|
||||||
|
physics_.reset();
|
||||||
|
physics_ = std::make_unique<VehiclePhysics>(world_, root_.local, *this, *model_, tuning_ctx_);
|
||||||
|
OnPhysicsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void game::Vehicle::WriteTuning(net::OutMessage& msg) const
|
void game::Vehicle::WriteTuning(net::OutMessage& msg) const
|
||||||
{
|
{
|
||||||
net::WriteRGB(msg, tuning_.primary_color);
|
// write colors
|
||||||
|
for (const auto& color : tuning_ctx_.colors)
|
||||||
// wheels
|
{
|
||||||
msg.Write<net::TuningPartIdx>(tuning_.wheels_idx);
|
net::WriteRGB(msg, color);
|
||||||
net::WriteRGB(msg, tuning_.wheel_color);
|
}
|
||||||
|
|
||||||
|
// write wheel models
|
||||||
|
for (const auto& wheel : tuning_ctx_.wheels)
|
||||||
|
{
|
||||||
|
msg.Write(net::ModelName(wheel.modelname));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PHYSICS
|
||||||
|
|
||||||
|
game::VehiclePhysics::VehiclePhysics(collision::DynamicsWorld& world, Transform& transform,
|
||||||
|
collision::ObjectCallback& obj_cb, const assets::VehicleModel& model,
|
||||||
|
const VehicleTuningContext& tuning)
|
||||||
|
: world_(world), motion_(transform)
|
||||||
|
{
|
||||||
|
|
||||||
|
// setup chassis rigidbody
|
||||||
|
btCollisionShape* shape = model.GetModel()->GetColShape();
|
||||||
|
if (!shape)
|
||||||
|
throw std::runtime_error("Making vehicle with no shape");
|
||||||
|
|
||||||
|
btVector3 local_inertia(0, 0, 0);
|
||||||
|
shape->calculateLocalInertia(tuning.mass, local_inertia);
|
||||||
|
|
||||||
|
btRigidBody::btRigidBodyConstructionInfo rb_info(tuning.mass, &motion_, shape, local_inertia);
|
||||||
|
body_ = std::make_unique<btRigidBody>(rb_info);
|
||||||
|
// body_->setActivationState(DISABLE_DEACTIVATION);
|
||||||
|
|
||||||
|
collision::SetObjectInfo(body_.get(), collision::OT_ENTITY, collision::OF_NOTIFY_CONTACT, &obj_cb);
|
||||||
|
|
||||||
|
// setup vehicle
|
||||||
|
btRaycastVehicle::btVehicleTuning bt_tuning;
|
||||||
|
vehicle_ = std::make_unique<collision::RaycastVehicle>(bt_tuning, body_.get(), &world_.GetVehicleRaycaster());
|
||||||
|
vehicle_->setCoordinateSystem(0, 2, 1);
|
||||||
|
|
||||||
|
// setup wheels
|
||||||
|
// btVector3 wheelDirectionCS0(0, -1, 0);
|
||||||
|
// btVector3 wheelAxleCS(-1, 0, 0);
|
||||||
|
btVector3 wheelDirectionCS0(0, 0, -1);
|
||||||
|
btVector3 wheelAxleCS(1, 0, 0);
|
||||||
|
|
||||||
|
const auto& model_wheels = model.GetWheels();
|
||||||
|
|
||||||
|
size_t num_wheels = model_wheels.size();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_wheels; ++i)
|
||||||
|
{
|
||||||
|
const auto& wheel_mdl = model_wheels[i];
|
||||||
|
const auto& wheel_tun = tuning.wheels[i];
|
||||||
|
|
||||||
|
// float wheelRadius = wheel_tun.radius;
|
||||||
|
|
||||||
|
// float friction = wheel_tun.friction
|
||||||
|
// float suspensionStiffness = 50.0f;
|
||||||
|
// // float suspensionDamping = 2.3f;
|
||||||
|
// // float suspensionCompression = 4.4f;
|
||||||
|
// float suspensionRestLength = 0.3f;
|
||||||
|
// float rollInfluence = 0.3f;
|
||||||
|
|
||||||
|
// float maxSuspensionForce = 90000.0f;
|
||||||
|
// float maxSuspensionTravelCm = 15.0f;
|
||||||
|
|
||||||
|
float k = 0.2f;
|
||||||
|
|
||||||
|
// if (!is_front)
|
||||||
|
// friction *= 1.5f;
|
||||||
|
|
||||||
|
btVector3 wheel_pos(wheel_mdl.position.x, wheel_mdl.position.y, wheel_mdl.position.z + wheel_tun.z_offset);
|
||||||
|
|
||||||
|
auto& wi = vehicle_->addWheel(wheel_pos, wheelDirectionCS0, wheelAxleCS, wheel_tun.suspension_rest_length, wheel_tun.radius,
|
||||||
|
bt_tuning, wheel_tun.front);
|
||||||
|
|
||||||
|
wi.m_suspensionStiffness = wheel_tun.suspension_stiffness;
|
||||||
|
|
||||||
|
wi.m_wheelsDampingCompression = k * 2.0 * btSqrt(wi.m_suspensionStiffness); // vehicleTuning.suspensionCompression;
|
||||||
|
wi.m_wheelsDampingRelaxation = k * 3.3 * btSqrt(wi.m_suspensionStiffness); // vehicleTuning.suspensionDamping;
|
||||||
|
|
||||||
|
wi.m_frictionSlip = wheel_tun.friction;
|
||||||
|
|
||||||
|
wi.m_rollInfluence = wheel_tun.roll_influence;
|
||||||
|
wi.m_maxSuspensionForce = wheel_tun.suspension_max_force;
|
||||||
|
wi.m_maxSuspensionTravelCm = wheel_tun.suspension_travel * 100.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& bt_world = world_.GetBtWorld();
|
||||||
|
bt_world.addRigidBody(body_.get(), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::AllFilter);
|
||||||
|
bt_world.addAction(vehicle_.get());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
game::VehiclePhysics::~VehiclePhysics()
|
||||||
|
{
|
||||||
|
auto& bt_world = world_.GetBtWorld();
|
||||||
|
bt_world.removeRigidBody(body_.get());
|
||||||
|
bt_world.removeAction(vehicle_.get());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,11 +6,11 @@
|
|||||||
#include "assets/vehiclemdl.hpp"
|
#include "assets/vehiclemdl.hpp"
|
||||||
#include "collision/motionstate.hpp"
|
#include "collision/motionstate.hpp"
|
||||||
#include "collision/raycastvehicle.hpp"
|
#include "collision/raycastvehicle.hpp"
|
||||||
#include "entity.hpp"
|
|
||||||
#include "world.hpp"
|
|
||||||
#include "vehicle_sync.hpp"
|
|
||||||
#include "deform_grid.hpp"
|
#include "deform_grid.hpp"
|
||||||
|
#include "entity.hpp"
|
||||||
|
#include "vehicle_sync.hpp"
|
||||||
#include "vehicle_tuning.hpp"
|
#include "vehicle_tuning.hpp"
|
||||||
|
#include "world.hpp"
|
||||||
|
|
||||||
namespace game
|
namespace game
|
||||||
{
|
{
|
||||||
@ -33,6 +33,26 @@ enum VehicleInputType
|
|||||||
VIN_HANDBRAKE,
|
VIN_HANDBRAKE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class VehiclePhysics
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VehiclePhysics(collision::DynamicsWorld& world, Transform& transform, collision::ObjectCallback& obj_cb,
|
||||||
|
const assets::VehicleModel& model, const VehicleTuningContext& tuning);
|
||||||
|
|
||||||
|
DELETE_COPY_MOVE(VehiclePhysics)
|
||||||
|
|
||||||
|
btRigidBody& GetBtBody() { return *body_; }
|
||||||
|
collision::RaycastVehicle& GetBtVehicle() { return *vehicle_; }
|
||||||
|
|
||||||
|
~VehiclePhysics();
|
||||||
|
|
||||||
|
private:
|
||||||
|
collision::DynamicsWorld& world_;
|
||||||
|
collision::MotionState motion_;
|
||||||
|
std::unique_ptr<btRigidBody> body_;
|
||||||
|
std::unique_ptr<collision::RaycastVehicle> vehicle_;
|
||||||
|
};
|
||||||
|
|
||||||
class Vehicle : public Entity
|
class Vehicle : public Entity
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -48,10 +68,8 @@ public:
|
|||||||
void SetInput(VehicleInputType type, bool enable);
|
void SetInput(VehicleInputType type, bool enable);
|
||||||
void SetInputs(VehicleInputFlags inputs) { in_ = inputs; }
|
void SetInputs(VehicleInputFlags inputs) { in_ = inputs; }
|
||||||
|
|
||||||
glm::vec3 GetPosition() const;
|
|
||||||
void SetPosition(const glm::vec3& pos);
|
void SetPosition(const glm::vec3& pos);
|
||||||
|
|
||||||
glm::quat GetRotation() const;
|
|
||||||
float GetSpeed() const;
|
float GetSpeed() const;
|
||||||
|
|
||||||
void SetSteering(bool analog, float value = 0.0f);
|
void SetSteering(bool analog, float value = 0.0f);
|
||||||
@ -60,9 +78,10 @@ public:
|
|||||||
|
|
||||||
const std::string& GetModelName() const { return tuning_.model; }
|
const std::string& GetModelName() const { return tuning_.model; }
|
||||||
const std::shared_ptr<const assets::VehicleModel>& GetModel() const { return model_; }
|
const std::shared_ptr<const assets::VehicleModel>& GetModel() const { return model_; }
|
||||||
const VehicleTuning& GetTuning() const { return tuning_; }
|
|
||||||
|
|
||||||
virtual ~Vehicle();
|
const VehicleTuning& GetTuning() const { return tuning_; }
|
||||||
|
const std::shared_ptr<const VehicleTuningList>& GetTuningList() const { return tuninglist_; }
|
||||||
|
const VehicleTuningContext& GetTuningResult() const { return tuning_ctx_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ProcessInput();
|
void ProcessInput();
|
||||||
@ -77,26 +96,28 @@ private:
|
|||||||
void Deform(const glm::vec3& pos, const glm::vec3& deform, float radius);
|
void Deform(const glm::vec3& pos, const glm::vec3& deform, float radius);
|
||||||
void SendDeformMsg(const net::PositionQ& pos, const net::PositionQ& deform);
|
void SendDeformMsg(const net::PositionQ& pos, const net::PositionQ& deform);
|
||||||
|
|
||||||
|
void ApplyTuning(const VehicleTuning& tuning);
|
||||||
|
|
||||||
void WriteTuning(net::OutMessage& msg) const;
|
void WriteTuning(net::OutMessage& msg) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
btRigidBody& GetBtBody() { return *body_; }
|
VehiclePhysics* GetPhysics() { return physics_.get(); }
|
||||||
|
virtual void OnPhysicsChanged() {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VehicleTuning tuning_;
|
VehicleTuning tuning_;
|
||||||
std::shared_ptr<const assets::VehicleModel> model_;
|
std::shared_ptr<const assets::VehicleModel> model_;
|
||||||
|
std::shared_ptr<const VehicleTuningList> tuninglist_;
|
||||||
|
|
||||||
collision::MotionState motion_;
|
VehicleTuningContext tuning_ctx_;
|
||||||
std::unique_ptr<btRigidBody> body_;
|
|
||||||
std::unique_ptr<collision::RaycastVehicle> vehicle_;
|
std::unique_ptr<VehiclePhysics> physics_;
|
||||||
|
|
||||||
float steering_ = 0.0f;
|
float steering_ = 0.0f;
|
||||||
bool steering_analog_ = false;
|
bool steering_analog_ = false;
|
||||||
float target_steering_ = 0.0f;
|
float target_steering_ = 0.0f;
|
||||||
float wheel_z_offset_ = 0.0f;
|
|
||||||
|
|
||||||
size_t num_wheels_ = 0;
|
std::vector<VehicleWheelState> wheels_;
|
||||||
std::array<VehicleWheelState, MAX_WHEELS> wheels_;
|
|
||||||
|
|
||||||
VehicleFlags flags_ = VF_NONE;
|
VehicleFlags flags_ = VF_NONE;
|
||||||
VehicleSyncState sync_[2];
|
VehicleSyncState sync_[2];
|
||||||
|
|||||||
218
src/game/vehicle_tuning.cpp
Normal file
218
src/game/vehicle_tuning.cpp
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
#include "vehicle_tuning.hpp"
|
||||||
|
|
||||||
|
#include "assets/cmdfile.hpp"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
static float game::VehicleTuningContext::* GetCtxVariablePointer(const std::string& name)
|
||||||
|
{
|
||||||
|
if (name == "mass")
|
||||||
|
return &game::VehicleTuningContext::mass;
|
||||||
|
if (name == "engine_force")
|
||||||
|
return &game::VehicleTuningContext::engine_force;
|
||||||
|
if (name == "braking_force")
|
||||||
|
return &game::VehicleTuningContext::braking_force;
|
||||||
|
|
||||||
|
throw std::runtime_error("tuning list: invalid variable " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float game::VehicleWheelTuningContext::* GetWheelVariablePointer(const std::string& name)
|
||||||
|
{
|
||||||
|
if (name == "radius")
|
||||||
|
return &game::VehicleWheelTuningContext::radius;
|
||||||
|
if (name == "z_offset")
|
||||||
|
return &game::VehicleWheelTuningContext::z_offset;
|
||||||
|
if (name == "friction")
|
||||||
|
return &game::VehicleWheelTuningContext::friction;
|
||||||
|
if (name == "suspension_stiffness")
|
||||||
|
return &game::VehicleWheelTuningContext::suspension_stiffness;
|
||||||
|
if (name == "suspension_max_force")
|
||||||
|
return &game::VehicleWheelTuningContext::suspension_max_force;
|
||||||
|
if (name == "suspension_rest_length")
|
||||||
|
return &game::VehicleWheelTuningContext::suspension_rest_length;
|
||||||
|
if (name == "suspension_travel")
|
||||||
|
return &game::VehicleWheelTuningContext::suspension_travel;
|
||||||
|
if (name == "roll_influence")
|
||||||
|
return &game::VehicleWheelTuningContext::roll_influence;
|
||||||
|
if (name == "steering_factor")
|
||||||
|
return &game::VehicleWheelTuningContext::steering_factor;
|
||||||
|
if (name == "braking_factor")
|
||||||
|
return &game::VehicleWheelTuningContext::braking_factor;
|
||||||
|
if (name == "engine_factor")
|
||||||
|
return &game::VehicleWheelTuningContext::engine_factor;
|
||||||
|
|
||||||
|
throw std::runtime_error("tuning list: invalid wheel variable " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ApplyOp(float& var, const std::string& op, float value)
|
||||||
|
{
|
||||||
|
if (op == "+=")
|
||||||
|
var += value;
|
||||||
|
else if (op == "-=")
|
||||||
|
var -= value;
|
||||||
|
else if (op == "*=")
|
||||||
|
var *= value;
|
||||||
|
else if (op == "/=")
|
||||||
|
var /= value;
|
||||||
|
else
|
||||||
|
var = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool CheckWheelCond(const game::VehicleWheelTuningContext& wheel_ctx, const std::string& cond)
|
||||||
|
{
|
||||||
|
if (cond == "front" && !wheel_ctx.front)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (cond == "rear" && wheel_ctx.front)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t ParseColor(uint32_t c)
|
||||||
|
{
|
||||||
|
auto r = (c >> 16) & 0xFF;
|
||||||
|
auto g = (c >> 8) & 0xFF;
|
||||||
|
auto b = c & 0xFF;
|
||||||
|
return 0xFF000000 | (b << 16) | (g << 8) | r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static game::VehicleTuningFunction ParseTuningFunction(std::istringstream& iss)
|
||||||
|
{
|
||||||
|
std::string func_name;
|
||||||
|
iss >> func_name;
|
||||||
|
|
||||||
|
if (func_name == "set")
|
||||||
|
{
|
||||||
|
std::string var_name, op;
|
||||||
|
float value;
|
||||||
|
iss >> var_name >> op >> value;
|
||||||
|
|
||||||
|
auto var_ptr = GetCtxVariablePointer(var_name);
|
||||||
|
|
||||||
|
return [var_ptr, op, value](game::VehicleTuningContext& ctx) {
|
||||||
|
ApplyOp(ctx.*var_ptr, op, value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (func_name == "setcolor")
|
||||||
|
{
|
||||||
|
size_t color_idx;
|
||||||
|
uint32_t color;
|
||||||
|
iss >> color_idx >> std::hex >> color >> std::dec;
|
||||||
|
|
||||||
|
if (color_idx >= 4)
|
||||||
|
throw std::runtime_error("tuning list: invalid color index");
|
||||||
|
|
||||||
|
color = ParseColor(color);
|
||||||
|
|
||||||
|
return [color_idx, color](game::VehicleTuningContext& ctx) {
|
||||||
|
ctx.colors[color_idx] = color;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (func_name == "setwheel")
|
||||||
|
{
|
||||||
|
std::string wheel_cond, var_name, op;
|
||||||
|
float value;
|
||||||
|
|
||||||
|
iss >> wheel_cond >> var_name >> op >> value;
|
||||||
|
|
||||||
|
auto var_ptr = GetWheelVariablePointer(var_name);
|
||||||
|
|
||||||
|
return [wheel_cond, var_ptr, op, value](game::VehicleTuningContext& ctx) {
|
||||||
|
for (auto& wheel : ctx.wheels)
|
||||||
|
{
|
||||||
|
if (CheckWheelCond(wheel, wheel_cond))
|
||||||
|
ApplyOp(wheel.*var_ptr, op, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (func_name == "setwheelmodel")
|
||||||
|
{
|
||||||
|
std::string wheel_cond, modelname;
|
||||||
|
iss >> wheel_cond >> modelname;
|
||||||
|
|
||||||
|
return [wheel_cond, modelname](game::VehicleTuningContext& ctx) {
|
||||||
|
for (auto& wheel : ctx.wheels)
|
||||||
|
{
|
||||||
|
if (CheckWheelCond(wheel, wheel_cond))
|
||||||
|
wheel.modelname = modelname;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("tuning list: unknown function " + func_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<const game::VehicleTuningList> game::VehicleTuningList::LoadFromFile(const std::string& filename)
|
||||||
|
{
|
||||||
|
auto tuninglist = std::make_unique<VehicleTuningList>();
|
||||||
|
|
||||||
|
if (!fs::FileExists(filename))
|
||||||
|
return tuninglist; // empty
|
||||||
|
|
||||||
|
VehicleTuningGroup* current_group = nullptr;
|
||||||
|
VehicleTuningPart* current_part = nullptr;
|
||||||
|
|
||||||
|
auto process_command = [&](const std::string& command, std::istringstream& iss) {
|
||||||
|
if (command == "group")
|
||||||
|
{
|
||||||
|
VehicleTuningGroup group;
|
||||||
|
iss >> group.id;
|
||||||
|
group.displayname = assets::ParseString(iss);
|
||||||
|
|
||||||
|
tuninglist->groups.emplace_back(std::move(group));
|
||||||
|
current_group = &tuninglist->groups.back();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (command == "part")
|
||||||
|
{
|
||||||
|
if (!current_group)
|
||||||
|
throw std::runtime_error("tuning list: part without active group");
|
||||||
|
|
||||||
|
VehicleTuningPart part;
|
||||||
|
iss >> part.id >> part.price;
|
||||||
|
part.displayname = assets::ParseString(iss);
|
||||||
|
|
||||||
|
current_part = &(current_group->parts[part.id] = std::move(part));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (command == "default")
|
||||||
|
{
|
||||||
|
tuninglist->default_funcs.emplace_back(ParseTuningFunction(iss));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (command == "mod")
|
||||||
|
{
|
||||||
|
if (!current_part)
|
||||||
|
throw std::runtime_error("tuning list: mod without active part");
|
||||||
|
|
||||||
|
current_part->funcs.emplace_back(ParseTuningFunction(iss));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
assets::LoadCMDFile(filename, [&](const std::string& command, std::istringstream& iss) {
|
||||||
|
|
||||||
|
if (process_command(command, iss))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (command == "include")
|
||||||
|
{
|
||||||
|
std::string include_name;
|
||||||
|
iss >> include_name;
|
||||||
|
|
||||||
|
assets::LoadCMDFile("data/" + include_name + ".tun", [&](const std::string& command, std::istringstream& iss) {
|
||||||
|
process_command(command, iss);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return tuninglist;
|
||||||
|
}
|
||||||
@ -1,18 +1,72 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace game
|
namespace game
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct VehicleWheelTuningContext
|
||||||
|
{
|
||||||
|
bool front;
|
||||||
|
std::string modelname;
|
||||||
|
float radius;
|
||||||
|
float z_offset;
|
||||||
|
float friction;
|
||||||
|
float suspension_stiffness;
|
||||||
|
float suspension_max_force;
|
||||||
|
float suspension_rest_length;
|
||||||
|
float suspension_travel;
|
||||||
|
float roll_influence;
|
||||||
|
float steering_factor;
|
||||||
|
float braking_factor;
|
||||||
|
float engine_factor;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VehicleTuningContext
|
||||||
|
{
|
||||||
|
std::array<uint32_t, 4> colors;
|
||||||
|
float mass;
|
||||||
|
float engine_force;
|
||||||
|
float braking_force;
|
||||||
|
std::vector<VehicleWheelTuningContext> wheels;
|
||||||
|
};
|
||||||
|
|
||||||
|
using VehicleTuningFunction = std::function<void(VehicleTuningContext&)>;
|
||||||
|
|
||||||
|
struct VehicleTuningPart
|
||||||
|
{
|
||||||
|
std::string id;
|
||||||
|
std::string displayname;
|
||||||
|
uint32_t price;
|
||||||
|
|
||||||
|
std::vector<VehicleTuningFunction> funcs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VehicleTuningGroup
|
||||||
|
{
|
||||||
|
std::string id;
|
||||||
|
std::string displayname;
|
||||||
|
std::map<std::string, VehicleTuningPart> parts;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VehicleTuningList
|
||||||
|
{
|
||||||
|
std::vector<VehicleTuningFunction> default_funcs;
|
||||||
|
std::vector<VehicleTuningGroup> groups;
|
||||||
|
|
||||||
|
static std::unique_ptr<const VehicleTuningList> LoadFromFile(const std::string& filename);
|
||||||
|
};
|
||||||
|
|
||||||
struct VehicleTuning
|
struct VehicleTuning
|
||||||
{
|
{
|
||||||
std::string model;
|
std::string model;
|
||||||
|
std::map<std::string, std::string> parts; // group : part
|
||||||
uint32_t primary_color = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
size_t wheels_idx = 0;
|
|
||||||
uint32_t wheel_color = 0xFFFFFFFF;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -128,7 +128,7 @@ void game::view::VehicleView::Draw(const DrawArgs& args)
|
|||||||
gfx::DrawSurfaceCmd cmd;
|
gfx::DrawSurfaceCmd cmd;
|
||||||
cmd.surface = &surface;
|
cmd.surface = &surface;
|
||||||
cmd.matrices = &root_.matrix;
|
cmd.matrices = &root_.matrix;
|
||||||
cmd.color = &color_;
|
cmd.color = &colors_[0];
|
||||||
args.dlist.AddSurface(cmd);
|
args.dlist.AddSurface(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,28 +188,29 @@ void game::view::VehicleView::InitMesh()
|
|||||||
|
|
||||||
bool game::view::VehicleView::ReadTuning(net::InMessage& msg)
|
bool game::view::VehicleView::ReadTuning(net::InMessage& msg)
|
||||||
{
|
{
|
||||||
uint32_t color, wheel_color;
|
// read colors
|
||||||
net::TuningPartIdx wheel_idx;
|
for (size_t i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
const auto& tuninglist = model_->GetTuningList();
|
uint32_t color;
|
||||||
|
|
||||||
if (!net::ReadRGB(msg, color))
|
if (!net::ReadRGB(msg, color))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
color_ = glm::unpackUnorm4x8(color);
|
colors_[i] = glm::unpackUnorm4x8(color);
|
||||||
|
}
|
||||||
// wheels
|
|
||||||
if (!msg.Read(wheel_idx) || !net::ReadRGB(msg, wheel_color))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto wheelmodel = wheel_idx < tuninglist.wheels.size() ? assets::CacheManager::GetModel("data/" + tuninglist.wheels[wheel_idx].model + ".mdl") : nullptr;
|
|
||||||
glm::vec3 wheelcolor = glm::unpackUnorm4x8(wheel_color);
|
|
||||||
|
|
||||||
|
// read wheel models
|
||||||
for (size_t i = 0; i < wheels_.size(); ++i)
|
for (size_t i = 0; i < wheels_.size(); ++i)
|
||||||
{
|
{
|
||||||
auto& wheel = wheels_[i];
|
net::ModelName wheelmodel_fixed;
|
||||||
wheel.model = wheelmodel ? wheelmodel : model_->GetWheels()[i].model;
|
|
||||||
wheel.color = glm::vec4(wheelcolor, 1.0f);
|
if (!msg.Read(wheelmodel_fixed))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string wheel_model_name = wheelmodel_fixed;
|
||||||
|
|
||||||
|
wheels_[i].model = !wheel_model_name.empty() ? assets::CacheManager::GetModel("data/" + wheel_model_name + ".mdl") : model_->GetWheels()[i].model;
|
||||||
|
wheels_[i].color = colors_[1]; // TODO: dynamic?;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -55,7 +55,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
std::shared_ptr<const assets::VehicleModel> model_;
|
std::shared_ptr<const assets::VehicleModel> model_;
|
||||||
assets::Mesh mesh_;
|
assets::Mesh mesh_;
|
||||||
glm::vec4 color_;
|
glm::vec4 colors_[4];
|
||||||
|
|
||||||
game::VehicleSyncState sync_;
|
game::VehicleSyncState sync_;
|
||||||
std::vector<VehicleWheelViewInfo> wheels_;
|
std::vector<VehicleWheelViewInfo> wheels_;
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define FEKAL_VERSION 2026032901
|
#define FEKAL_VERSION 2026041201
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user