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/skeleton.hpp"
|
||||
"src/assets/skeleton.cpp"
|
||||
"src/assets/vehicle_tuning_list.hpp"
|
||||
"src/assets/vehicle_tuning_list.cpp"
|
||||
"src/assets/vehiclemdl.hpp"
|
||||
"src/assets/vehiclemdl.cpp"
|
||||
"src/collision/dynamicsworld.hpp"
|
||||
@ -157,6 +155,8 @@ set(SERVER_ONLY_SOURCES
|
||||
"src/game/tuning_world.hpp"
|
||||
"src/game/tuning_world.cpp"
|
||||
"src/game/usable.hpp"
|
||||
"src/game/vehicle_tuning.hpp"
|
||||
"src/game/vehicle_tuning.cpp"
|
||||
"src/game/vehicle.hpp"
|
||||
"src/game/vehicle.cpp"
|
||||
"src/game/world.hpp"
|
||||
|
||||
@ -9,12 +9,12 @@ void assets::LoadCMDStream(std::istream& is, CmdCallback handler)
|
||||
|
||||
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
|
||||
continue;
|
||||
|
||||
// skip whitespace
|
||||
line.erase(0, line.find_first_not_of(" \t"));
|
||||
|
||||
std::istringstream iss(line);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
#include "model.hpp"
|
||||
#include "utils/transform.hpp"
|
||||
#include "vehicle_tuning_list.hpp"
|
||||
|
||||
namespace assets
|
||||
{
|
||||
@ -36,13 +35,11 @@ public:
|
||||
const std::shared_ptr<const Model>& GetModel() const { return basemodel_; }
|
||||
const std::vector<VehicleWheel>& GetWheels() const { return wheels_; }
|
||||
const Transform* GetLocation(const std::string& name) const;
|
||||
const VehicleTuningList& GetTuningList() const { return *tuninglist_; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<const Model> basemodel_;
|
||||
std::vector<VehicleWheel> wheels_;
|
||||
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)
|
||||
{
|
||||
InitSeats();
|
||||
OnPhysicsChanged();
|
||||
}
|
||||
|
||||
void game::DrivableVehicle::OnPhysicsChanged()
|
||||
{
|
||||
// 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)
|
||||
@ -90,7 +94,7 @@ static std::string GetColorTextPrefix(uint32_t color)
|
||||
|
||||
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";
|
||||
|
||||
const auto& veh = *GetModel();
|
||||
|
||||
@ -20,6 +20,8 @@ public:
|
||||
|
||||
DrivableVehicle(World& world, const VehicleTuning& tuning);
|
||||
|
||||
virtual void OnPhysicsChanged() override;
|
||||
|
||||
virtual bool QueryUseTarget(PlayerCharacter& character, uint32_t target_id, UseTargetQueryResult& res) override;
|
||||
virtual void Use(PlayerCharacter& character, uint32_t target_id) override;
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ void game::NpcCharacter::VehicleChanged()
|
||||
{
|
||||
roads_ = world_.GetMap().GetGraph("roads");
|
||||
|
||||
seg_start_ = GetVehicle()->GetPosition();
|
||||
seg_start_ = GetVehicle()->GetRootTransform().position;
|
||||
|
||||
size_t start_node = 0;
|
||||
float min_dist = std::numeric_limits<float>().infinity();
|
||||
@ -87,8 +87,10 @@ void game::NpcCharacter::VehicleThink()
|
||||
if (!IsDriver() || !GetVehicle() || !roads_)
|
||||
return;
|
||||
|
||||
glm::vec3 pos = GetVehicle()->GetPosition();
|
||||
glm::quat rot = GetVehicle()->GetRotation();
|
||||
const auto& vehicle_trans = GetVehicle()->GetRootTransform();
|
||||
|
||||
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 target = s->roads.nodes[s->node].position;
|
||||
|
||||
@ -56,9 +56,10 @@ game::OpenWorld::OpenWorld() : EnterableWorld("openworld")
|
||||
// initial twingo
|
||||
VehicleTuning twingo_tuning;
|
||||
twingo_tuning.model = "twingo";
|
||||
twingo_tuning.primary_color = 0x0077FF;
|
||||
twingo_tuning.wheels_idx = 1; // enkei
|
||||
twingo_tuning.wheel_color = 0x00FF00;
|
||||
twingo_tuning.parts["primarycolor"] = "orange";
|
||||
// twingo_tuning.primary_color = 0x0077FF;
|
||||
// twingo_tuning.wheels_idx = 1; // enkei
|
||||
// twingo_tuning.wheel_color = 0x00FF00;
|
||||
|
||||
auto& veh = Spawn<game::DrivableVehicle>(twingo_tuning);
|
||||
veh.SetPosition({110.0f, 100.0f, 5.0f});
|
||||
@ -83,11 +84,23 @@ game::DrivableVehicle& game::OpenWorld::SpawnRandomVehicle()
|
||||
{
|
||||
game::VehicleTuning tuning;
|
||||
tuning.model = GetRandomCarModel();
|
||||
tuning.primary_color = GetRandomColor24();
|
||||
// tuning.primary_color = GetRandomColor24();
|
||||
|
||||
auto& vehicle = Spawn<game::DrivableVehicle>(tuning);
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#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) :
|
||||
@ -32,7 +31,7 @@ void game::TuningWorld::OnVehicleJoined(DrivableVehicle& vehicle)
|
||||
throw std::runtime_error("vehicle joined to tuning without ACTIVE player driver??");
|
||||
|
||||
vehicle_ = &vehicle;
|
||||
tuning_list_ = &vehicle.GetModel()->GetTuningList();
|
||||
tuning_list_ = vehicle.GetTuningList().get();
|
||||
player_ = player;
|
||||
|
||||
Setup();
|
||||
@ -54,73 +53,133 @@ const std::string& game::TuningWorld::GetOccupantName() const
|
||||
void game::TuningWorld::Setup()
|
||||
{
|
||||
tuning_ = vehicle_->GetTuning();
|
||||
UpdateTuningVals();
|
||||
// UpdateTuningVals();
|
||||
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;
|
||||
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();
|
||||
struct SliderState
|
||||
{
|
||||
const VehicleTuningGroup* group;
|
||||
int idx = 0;
|
||||
std::vector<std::string> ids;
|
||||
};
|
||||
|
||||
on_select(0);
|
||||
slider.SetOnSelect(on_select);
|
||||
}
|
||||
std::string current_part;
|
||||
|
||||
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);
|
||||
}
|
||||
auto current_it = tuning_.parts.find(group.id);
|
||||
if (current_it != tuning_.parts.end())
|
||||
{
|
||||
current_part = current_it->second;
|
||||
}
|
||||
|
||||
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 state = std::make_shared<SliderState>();
|
||||
state->group = &group;
|
||||
|
||||
auto on_select = [&slider, &idx, &tuning_list, on_change = std::move(on_change)] (int dir) {
|
||||
auto& wheels = tuning_list.wheels;
|
||||
state->ids.reserve(num_parts);
|
||||
size_t i = 0;
|
||||
for (const auto& part : group.parts)
|
||||
{
|
||||
state->ids.push_back(part.first);
|
||||
|
||||
if (dir < 0 && idx == 0)
|
||||
return;
|
||||
if (part.first == current_part)
|
||||
state->idx = i;
|
||||
|
||||
if (dir > 0 && (idx + 1) >= wheels.size())
|
||||
return;
|
||||
++i;
|
||||
}
|
||||
|
||||
idx += dir;
|
||||
auto& slider = menu.AddItem(game::RM_SELECT, group.displayname);
|
||||
|
||||
auto on_select = [&slider, this, state](int dir) mutable {
|
||||
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;
|
||||
|
||||
auto& part_id = state->ids[state->idx];
|
||||
tuning_.parts[state->group->id] = part_id;
|
||||
slider.SetSelection(state->group->parts.at(part_id).displayname);
|
||||
|
||||
if (dir != 0)
|
||||
vehicle_->SetTuning(tuning_);
|
||||
|
||||
slider.SetSelection(tuning_list.wheels[idx].displayname);
|
||||
on_change();
|
||||
};
|
||||
|
||||
on_select(0);
|
||||
@ -133,14 +192,19 @@ void game::TuningWorld::DisplayTuningMenu()
|
||||
auto& menu = player_->DisplayMenu("tuning");
|
||||
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);
|
||||
AddColorSliders(menu, tun_wheel_color_, "kola", on_change);
|
||||
AddTuningGroupSelect(menu, group);
|
||||
}
|
||||
|
||||
auto& exit_btn = menu.AddItem(RM_BUTTON, "vylézt");
|
||||
|
||||
@ -26,9 +26,7 @@ public:
|
||||
private:
|
||||
void Setup();
|
||||
|
||||
void UpdateTuningVals();
|
||||
void UpdateTuning();
|
||||
|
||||
void AddTuningGroupSelect(game::RemoteMenu& menu, const VehicleTuningGroup& group);
|
||||
void DisplayTuningMenu();
|
||||
|
||||
void Reset();
|
||||
@ -42,17 +40,13 @@ private:
|
||||
// active player
|
||||
Player* player_ = nullptr;
|
||||
DrivableVehicle* vehicle_ = nullptr;
|
||||
const assets::VehicleTuningList* tuning_list_ = nullptr;
|
||||
const 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_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@ -15,87 +15,13 @@ static std::shared_ptr<const assets::VehicleModel> LoadVehicleModelByName(const
|
||||
|
||||
game::Vehicle::Vehicle(World& world, const VehicleTuning& tuning)
|
||||
: 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;
|
||||
|
||||
// setup chassis rigidbody
|
||||
float mass = 1000.0f;
|
||||
wheels_.resize(model_->GetWheels().size());
|
||||
|
||||
btCollisionShape* shape = model_->GetModel()->GetColShape();
|
||||
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());
|
||||
ApplyTuning(tuning);
|
||||
|
||||
// init deform
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void game::Vehicle::SetInput(VehicleInputType type, bool enable)
|
||||
@ -174,28 +99,18 @@ void game::Vehicle::SetInput(VehicleInputType type, bool enable)
|
||||
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)
|
||||
{
|
||||
auto t = body_->getWorldTransform();
|
||||
t.setOrigin(btVector3(pos.x, pos.y, pos.z));
|
||||
body_->setWorldTransform(t);
|
||||
}
|
||||
auto& body = physics_->GetBtBody();
|
||||
|
||||
glm::quat game::Vehicle::GetRotation() const
|
||||
{
|
||||
btQuaternion rot = body_->getWorldTransform().getRotation();
|
||||
return glm::quat(rot.w(), rot.x(), rot.y(), rot.z());
|
||||
auto t = body.getWorldTransform();
|
||||
t.setOrigin(btVector3(pos.x, pos.y, pos.z));
|
||||
body.setWorldTransform(t);
|
||||
}
|
||||
|
||||
float game::Vehicle::GetSpeed() const
|
||||
{
|
||||
return vehicle_->getCurrentSpeedKmHour();
|
||||
return physics_->GetBtVehicle().getCurrentSpeedKmHour();
|
||||
}
|
||||
|
||||
void game::Vehicle::SetSteering(bool analog, float value)
|
||||
@ -206,54 +121,48 @@ void game::Vehicle::SetSteering(bool analog, float value)
|
||||
|
||||
void game::Vehicle::SetTuning(const VehicleTuning& tuning)
|
||||
{
|
||||
tuning_ = tuning;
|
||||
ApplyTuning(tuning);
|
||||
|
||||
// send to clients
|
||||
auto msg = BeginEntMsg(net::EMSG_TUNING);
|
||||
WriteTuning(msg);
|
||||
}
|
||||
|
||||
game::Vehicle::~Vehicle()
|
||||
{
|
||||
auto& bt_world = world_.GetBtWorld();
|
||||
bt_world.removeRigidBody(body_.get());
|
||||
bt_world.removeAction(vehicle_.get());
|
||||
}
|
||||
|
||||
void game::Vehicle::ProcessInput()
|
||||
{
|
||||
// TODO: totally fix
|
||||
|
||||
//std::string nt = "";
|
||||
// std::string nt = "";
|
||||
|
||||
if (in_) {
|
||||
//nt += "in ";
|
||||
// body_->setActivationState(ACTIVE_TAG);
|
||||
body_->activate();
|
||||
if (in_)
|
||||
{
|
||||
// nt += "in ";
|
||||
// body_->setActivationState(ACTIVE_TAG);
|
||||
physics_->GetBtBody().activate();
|
||||
}
|
||||
else
|
||||
{
|
||||
//nt += "no in";
|
||||
// nt += "no in";
|
||||
}
|
||||
|
||||
//nt += std::to_string(body_->getActivationState());
|
||||
//SetNametag(nt);
|
||||
// nt += std::to_string(body_->getActivationState());
|
||||
// SetNametag(nt);
|
||||
|
||||
float t_delta = 1.0f / 25.0f;
|
||||
|
||||
// float steeringIncrement = .04 * 60;
|
||||
// float steeringClamp = .5;
|
||||
// float maxEngineForce = 7000;
|
||||
float maxEngineForce = 3200;
|
||||
float maxBreakingForce = 400;
|
||||
float maxEngineForce = tuning_ctx_.engine_force;
|
||||
float maxBreakingForce = tuning_ctx_.braking_force;
|
||||
|
||||
float speed = vehicle_->getCurrentSpeedKmHour();
|
||||
float speed = GetSpeed();
|
||||
if (glm::abs(speed) > 200.0f)
|
||||
maxEngineForce = 100.0f;
|
||||
|
||||
float engineForce = 0;
|
||||
float breakingForce = 0;
|
||||
|
||||
|
||||
float maxsc = .5f;
|
||||
float minsc = .08f;
|
||||
float sl = 130.f;
|
||||
@ -263,11 +172,10 @@ void game::Vehicle::ProcessInput()
|
||||
float steeringSpeed = steeringClamp * 5.0f;
|
||||
float steeringInc = steeringSpeed * t_delta;
|
||||
|
||||
|
||||
const bool in_forward = in_ & (1 << VIN_FORWARD);
|
||||
const bool in_backward = in_ & (1 << VIN_BACKWARD);
|
||||
const bool in_left = in_ & (1 << VIN_LEFT);
|
||||
const bool in_right = in_ & (1 << VIN_RIGHT);
|
||||
const bool in_right = in_ & (1 << VIN_RIGHT);
|
||||
|
||||
if (in_forward)
|
||||
{
|
||||
@ -287,7 +195,7 @@ void game::Vehicle::ProcessInput()
|
||||
// idle breaking
|
||||
if (!in_forward && !in_backward)
|
||||
{
|
||||
breakingForce = maxBreakingForce * 0.05f;
|
||||
breakingForce = 20.0f;
|
||||
}
|
||||
|
||||
if (!steering_analog_)
|
||||
@ -341,16 +249,29 @@ void game::Vehicle::ProcessInput()
|
||||
steering_ = -steeringClamp;
|
||||
}
|
||||
|
||||
vehicle_->applyEngineForce(engineForce, 0);
|
||||
vehicle_->applyEngineForce(engineForce, 1);
|
||||
auto& vehicle = physics_->GetBtVehicle();
|
||||
|
||||
vehicle_->setBrake(breakingForce * 0.1f, 0);
|
||||
vehicle_->setBrake(breakingForce * 0.1f, 1);
|
||||
vehicle_->setBrake(breakingForce, 2);
|
||||
vehicle_->setBrake(breakingForce, 3);
|
||||
for (size_t i = 0; i < wheels_.size(); ++i)
|
||||
{
|
||||
float engine_factor = tuning_ctx_.wheels[i].engine_factor;
|
||||
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)
|
||||
flags_ |= VF_ACCELERATING;
|
||||
@ -394,7 +315,6 @@ void game::Vehicle::UpdateCrash()
|
||||
PlaySound("crash", volume, pitch);
|
||||
no_crash_frames_ = 7 + rand() % 10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
crash_intensity_ = 0.0f;
|
||||
@ -402,12 +322,14 @@ void game::Vehicle::UpdateCrash()
|
||||
|
||||
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].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_);
|
||||
|
||||
for (size_t i = 0; i < num_wheels_; ++i)
|
||||
for (size_t i = 0; i < wheels_.size(); ++i)
|
||||
{
|
||||
auto& wheel = wheels_[i];
|
||||
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);
|
||||
}
|
||||
|
||||
if (curr.pos.x.value != base.pos.x.value ||
|
||||
curr.pos.y.value != base.pos.y.value ||
|
||||
if (curr.pos.x.value != base.pos.x.value || curr.pos.y.value != base.pos.y.value ||
|
||||
curr.pos.z.value != base.pos.z.value)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (curr.rot.x.value != base.rot.x.value ||
|
||||
curr.rot.y.value != base.rot.y.value ||
|
||||
if (curr.rot.x.value != base.rot.x.value || curr.rot.y.value != base.rot.y.value ||
|
||||
curr.rot.z.value != base.rot.z.value)
|
||||
{
|
||||
fields |= VSF_ROTATION;
|
||||
@ -471,7 +391,7 @@ game::VehicleSyncFieldFlags game::Vehicle::WriteState(net::OutMessage& msg, cons
|
||||
}
|
||||
|
||||
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 ||
|
||||
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;
|
||||
|
||||
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].speed, base.wheels[i].speed);
|
||||
@ -563,11 +483,147 @@ void game::Vehicle::SendDeformMsg(const net::PositionQ& pos, const net::Position
|
||||
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
|
||||
{
|
||||
net::WriteRGB(msg, tuning_.primary_color);
|
||||
// write colors
|
||||
for (const auto& color : tuning_ctx_.colors)
|
||||
{
|
||||
net::WriteRGB(msg, color);
|
||||
}
|
||||
|
||||
// wheels
|
||||
msg.Write<net::TuningPartIdx>(tuning_.wheels_idx);
|
||||
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 "collision/motionstate.hpp"
|
||||
#include "collision/raycastvehicle.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "world.hpp"
|
||||
#include "vehicle_sync.hpp"
|
||||
#include "deform_grid.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "vehicle_sync.hpp"
|
||||
#include "vehicle_tuning.hpp"
|
||||
#include "world.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
@ -33,6 +33,26 @@ enum VehicleInputType
|
||||
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
|
||||
{
|
||||
public:
|
||||
@ -48,10 +68,8 @@ public:
|
||||
void SetInput(VehicleInputType type, bool enable);
|
||||
void SetInputs(VehicleInputFlags inputs) { in_ = inputs; }
|
||||
|
||||
glm::vec3 GetPosition() const;
|
||||
void SetPosition(const glm::vec3& pos);
|
||||
|
||||
glm::quat GetRotation() const;
|
||||
float GetSpeed() const;
|
||||
|
||||
void SetSteering(bool analog, float value = 0.0f);
|
||||
@ -60,9 +78,10 @@ public:
|
||||
|
||||
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_; }
|
||||
|
||||
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:
|
||||
void ProcessInput();
|
||||
@ -77,26 +96,28 @@ private:
|
||||
void Deform(const glm::vec3& pos, const glm::vec3& deform, float radius);
|
||||
void SendDeformMsg(const net::PositionQ& pos, const net::PositionQ& deform);
|
||||
|
||||
void ApplyTuning(const VehicleTuning& tuning);
|
||||
|
||||
void WriteTuning(net::OutMessage& msg) const;
|
||||
|
||||
protected:
|
||||
btRigidBody& GetBtBody() { return *body_; }
|
||||
VehiclePhysics* GetPhysics() { return physics_.get(); }
|
||||
virtual void OnPhysicsChanged() {}
|
||||
|
||||
private:
|
||||
VehicleTuning tuning_;
|
||||
std::shared_ptr<const assets::VehicleModel> model_;
|
||||
std::shared_ptr<const VehicleTuningList> tuninglist_;
|
||||
|
||||
collision::MotionState motion_;
|
||||
std::unique_ptr<btRigidBody> body_;
|
||||
std::unique_ptr<collision::RaycastVehicle> vehicle_;
|
||||
VehicleTuningContext tuning_ctx_;
|
||||
|
||||
std::unique_ptr<VehiclePhysics> physics_;
|
||||
|
||||
float steering_ = 0.0f;
|
||||
bool steering_analog_ = false;
|
||||
float target_steering_ = 0.0f;
|
||||
float wheel_z_offset_ = 0.0f;
|
||||
|
||||
size_t num_wheels_ = 0;
|
||||
std::array<VehicleWheelState, MAX_WHEELS> wheels_;
|
||||
std::vector<VehicleWheelState> wheels_;
|
||||
|
||||
VehicleFlags flags_ = VF_NONE;
|
||||
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
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <array>
|
||||
|
||||
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
|
||||
{
|
||||
std::string model;
|
||||
|
||||
uint32_t primary_color = 0xFFFFFFFF;
|
||||
|
||||
size_t wheels_idx = 0;
|
||||
uint32_t wheel_color = 0xFFFFFFFF;
|
||||
std::map<std::string, std::string> parts; // group : part
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -128,7 +128,7 @@ void game::view::VehicleView::Draw(const DrawArgs& args)
|
||||
gfx::DrawSurfaceCmd cmd;
|
||||
cmd.surface = &surface;
|
||||
cmd.matrices = &root_.matrix;
|
||||
cmd.color = &color_;
|
||||
cmd.color = &colors_[0];
|
||||
args.dlist.AddSurface(cmd);
|
||||
}
|
||||
|
||||
@ -188,28 +188,29 @@ void game::view::VehicleView::InitMesh()
|
||||
|
||||
bool game::view::VehicleView::ReadTuning(net::InMessage& msg)
|
||||
{
|
||||
uint32_t color, wheel_color;
|
||||
net::TuningPartIdx wheel_idx;
|
||||
// read colors
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
{
|
||||
uint32_t color;
|
||||
|
||||
const auto& tuninglist = model_->GetTuningList();
|
||||
if (!net::ReadRGB(msg, color))
|
||||
return false;
|
||||
|
||||
if (!net::ReadRGB(msg, color))
|
||||
return false;
|
||||
|
||||
color_ = 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);
|
||||
colors_[i] = glm::unpackUnorm4x8(color);
|
||||
}
|
||||
|
||||
// read wheel models
|
||||
for (size_t i = 0; i < wheels_.size(); ++i)
|
||||
{
|
||||
auto& wheel = wheels_[i];
|
||||
wheel.model = wheelmodel ? wheelmodel : model_->GetWheels()[i].model;
|
||||
wheel.color = glm::vec4(wheelcolor, 1.0f);
|
||||
net::ModelName wheelmodel_fixed;
|
||||
|
||||
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;
|
||||
|
||||
@ -55,7 +55,7 @@ private:
|
||||
private:
|
||||
std::shared_ptr<const assets::VehicleModel> model_;
|
||||
assets::Mesh mesh_;
|
||||
glm::vec4 color_;
|
||||
glm::vec4 colors_[4];
|
||||
|
||||
game::VehicleSyncState sync_;
|
||||
std::vector<VehicleWheelViewInfo> wheels_;
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define FEKAL_VERSION 2026032901
|
||||
#define FEKAL_VERSION 2026041201
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user