Basic vehicle tuning
This commit is contained in:
parent
1c136bcc74
commit
627beffc65
@ -18,6 +18,8 @@ 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"
|
||||
|
||||
@ -23,3 +23,30 @@ void assets::LoadCMDFile(const std::string& filename,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string assets::ParseString(std::istringstream& iss)
|
||||
{
|
||||
std::string str;
|
||||
iss >> str;
|
||||
|
||||
if (!str.starts_with('"'))
|
||||
return str;
|
||||
|
||||
str = str.substr(1);
|
||||
|
||||
while (iss)
|
||||
{
|
||||
std::string tmp;
|
||||
iss >> tmp;
|
||||
str += ' ';
|
||||
str += tmp;
|
||||
|
||||
if (str.ends_with('"'))
|
||||
{
|
||||
str.pop_back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
@ -21,4 +21,6 @@ inline void ParseTransform(std::istringstream& iss, Transform& trans)
|
||||
iss >> trans.scale;
|
||||
}
|
||||
|
||||
std::string ParseString(std::istringstream& iss);
|
||||
|
||||
} // namespace assets
|
||||
24
src/assets/vehicle_tuning_list.cpp
Normal file
24
src/assets/vehicle_tuning_list.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#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;
|
||||
}
|
||||
27
src/assets/vehicle_tuning_list.hpp
Normal file
27
src/assets/vehicle_tuning_list.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#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,6 +48,9 @@ std::shared_ptr<const assets::VehicleModel> assets::VehicleModel::LoadFromFile(c
|
||||
}
|
||||
});
|
||||
|
||||
// tuning list
|
||||
veh->tuninglist_ = VehicleTuningList::LoadFromFile(filename + ".tun");
|
||||
|
||||
return veh;
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include "model.hpp"
|
||||
#include "utils/transform.hpp"
|
||||
#include "vehicle_tuning_list.hpp"
|
||||
|
||||
namespace assets
|
||||
{
|
||||
@ -35,11 +36,13 @@ 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_;
|
||||
|
||||
|
||||
};
|
||||
|
||||
@ -2,8 +2,7 @@
|
||||
#include "player_character.hpp"
|
||||
#include "utils/random.hpp"
|
||||
|
||||
game::DrivableVehicle::DrivableVehicle(World& world, std::string model_name, const glm::vec3& color)
|
||||
: Vehicle(world, std::move(model_name), color)
|
||||
game::DrivableVehicle::DrivableVehicle(World& world, const VehicleTuning& tuning) : Vehicle(world, tuning)
|
||||
{
|
||||
InitSeats();
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ struct VehicleSeat
|
||||
class DrivableVehicle : public Vehicle, public Usable
|
||||
{
|
||||
public:
|
||||
DrivableVehicle(World& world, std::string model_name, const glm::vec3& color);
|
||||
DrivableVehicle(World& world, const VehicleTuning& tuning);
|
||||
|
||||
virtual void Use(PlayerCharacter& character, uint32_t target_id) override;
|
||||
|
||||
|
||||
@ -36,6 +36,14 @@ static glm::vec3 GetRandomColor()
|
||||
return color;
|
||||
}
|
||||
|
||||
static uint32_t GetRandomColor24()
|
||||
{
|
||||
uint8_t r,g,b;
|
||||
r = rand() % 256;
|
||||
g = rand() % 256;
|
||||
b = rand() % 256;
|
||||
return (b << 16) | (g << 8) | r;
|
||||
}
|
||||
|
||||
game::OpenWorld::OpenWorld() : World("openworld")
|
||||
{
|
||||
@ -47,7 +55,14 @@ game::OpenWorld::OpenWorld() : World("openworld")
|
||||
SpawnBot();
|
||||
}
|
||||
|
||||
auto& veh = Spawn<game::DrivableVehicle>("twingo", glm::vec3{1.0f, 0.8f, 0.1f});
|
||||
// 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;
|
||||
|
||||
auto& veh = Spawn<game::DrivableVehicle>(twingo_tuning);
|
||||
veh.SetPosition({110.0f, 100.0f, 5.0f});
|
||||
|
||||
constexpr size_t in_row = 20;
|
||||
@ -59,7 +74,7 @@ game::OpenWorld::OpenWorld() : World("openworld")
|
||||
size_t row = i / in_row;
|
||||
glm::vec3 pos(62.0f + static_cast<float>(col) * 4.0f, 165.0f + static_cast<float>(row) * 7.0f, 7.0f);
|
||||
|
||||
auto& veh = Spawn<game::DrivableVehicle>(GetRandomCarModel(), GetRandomColor());
|
||||
auto& veh = SpawnRandomVehicle();
|
||||
veh.SetPosition(pos);
|
||||
});
|
||||
}
|
||||
@ -157,29 +172,32 @@ void game::OpenWorld::RemovePlayerCharacter(Player& player)
|
||||
}
|
||||
}
|
||||
|
||||
static game::DrivableVehicle& SpawnRandomVehicle(game::World& world)
|
||||
game::DrivableVehicle& game::OpenWorld::SpawnRandomVehicle()
|
||||
{
|
||||
auto roads = world.GetMap().GetGraph("roads");
|
||||
game::VehicleTuning tuning;
|
||||
tuning.model = GetRandomCarModel();
|
||||
tuning.primary_color = GetRandomColor24();
|
||||
|
||||
if (!roads)
|
||||
{
|
||||
throw std::runtime_error("SpawnRandomVehicle: no roads graph in map");
|
||||
}
|
||||
|
||||
size_t start_node = rand() % roads->nodes.size();
|
||||
// auto color = glm::vec3{0.3f, 0.3f, 0.3f};
|
||||
auto color = GetRandomColor();
|
||||
auto& vehicle = world.Spawn<game::DrivableVehicle>(GetRandomCarModel(), color);
|
||||
auto& vehicle = Spawn<game::DrivableVehicle>(tuning);
|
||||
// vehicle.SetNametag("bot (" + std::to_string(vehicle.GetEntNum()) + ")");
|
||||
vehicle.SetPosition(roads->nodes[start_node].position + glm::vec3{0.0f, 0.0f, 5.0f});
|
||||
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
void game::OpenWorld::SpawnBot()
|
||||
{
|
||||
auto& vehicle = SpawnRandomVehicle(*this);
|
||||
auto& driver = SpawnRandomCharacter<NpcCharacter>(*this);
|
||||
auto roads = GetMap().GetGraph("roads");
|
||||
|
||||
if (!roads)
|
||||
{
|
||||
throw std::runtime_error("SpawnBot: no roads graph in map");
|
||||
}
|
||||
|
||||
size_t start_node = rand() % roads->nodes.size();
|
||||
|
||||
auto& vehicle = SpawnRandomVehicle();
|
||||
vehicle.SetPosition(roads->nodes[start_node].position + glm::vec3{0.0f, 0.0f, 5.0f});
|
||||
|
||||
auto& driver = SpawnRandomCharacter<NpcCharacter>(*this);
|
||||
driver.SetVehicle(&vehicle, 0);
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "vehicle.hpp"
|
||||
#include "character.hpp"
|
||||
#include "usable.hpp"
|
||||
#include "drivable_vehicle.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
@ -31,6 +32,7 @@ private:
|
||||
void CreatePlayerCharacter(Player& player);
|
||||
void RemovePlayerCharacter(Player& player);
|
||||
|
||||
game::DrivableVehicle& SpawnRandomVehicle();
|
||||
void SpawnBot();
|
||||
|
||||
private:
|
||||
|
||||
@ -13,10 +13,9 @@ static std::shared_ptr<const assets::VehicleModel> LoadVehicleModelByName(const
|
||||
return assets::CacheManager::GetVehicleModel("data/" + model_name + ".veh");
|
||||
}
|
||||
|
||||
game::Vehicle::Vehicle(World& world, std::string model_name, const glm::vec3& color)
|
||||
: Entity(world, net::ET_VEHICLE), model_name_(model_name), model_(LoadVehicleModelByName(model_name)),
|
||||
motion_(root_.local),
|
||||
color_(color)
|
||||
game::Vehicle::Vehicle(World& world, const VehicleTuning& tuning)
|
||||
: Entity(world, net::ET_VEHICLE), tuning_(tuning), model_(LoadVehicleModelByName(tuning.model)),
|
||||
motion_(root_.local)
|
||||
{
|
||||
root_.local.position.z = 10.0f;
|
||||
|
||||
@ -37,8 +36,8 @@ game::Vehicle::Vehicle(World& world, std::string model_name, const glm::vec3& co
|
||||
collision::SetObjectInfo(body_.get(), collision::OT_ENTITY, collision::OF_NOTIFY_CONTACT, this);
|
||||
|
||||
// setup vehicle
|
||||
btRaycastVehicle::btVehicleTuning tuning;
|
||||
vehicle_ = std::make_unique<collision::RaycastVehicle>(tuning, body_.get(), &world_.GetVehicleRaycaster());
|
||||
btRaycastVehicle::btVehicleTuning bt_tuning;
|
||||
vehicle_ = std::make_unique<collision::RaycastVehicle>(bt_tuning, body_.get(), &world_.GetVehicleRaycaster());
|
||||
vehicle_->setCoordinateSystem(0, 2, 1);
|
||||
|
||||
// setup wheels
|
||||
@ -76,7 +75,7 @@ game::Vehicle::Vehicle(World& world, std::string model_name, const glm::vec3& co
|
||||
|
||||
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,
|
||||
tuning, is_front);
|
||||
bt_tuning, is_front);
|
||||
|
||||
wi.m_suspensionStiffness = suspensionStiffness;
|
||||
|
||||
@ -126,9 +125,8 @@ void game::Vehicle::SendInitData(Player& player, net::OutMessage& msg) const
|
||||
{
|
||||
Super::SendInitData(player, msg);
|
||||
|
||||
net::ModelName name(model_name_);
|
||||
msg.Write(name);
|
||||
net::WriteRGB(msg, color_); // primary color
|
||||
msg.Write(net::ModelName(tuning_.model));
|
||||
WriteTuning(msg);
|
||||
|
||||
// write state against default
|
||||
static const VehicleSyncState default_state;
|
||||
@ -553,3 +551,12 @@ void game::Vehicle::SendDeformMsg(const net::PositionQ& pos, const net::Position
|
||||
net::WritePositionQ(msg, pos);
|
||||
net::WritePositionQ(msg, deform);
|
||||
}
|
||||
|
||||
void game::Vehicle::WriteTuning(net::OutMessage& msg) const
|
||||
{
|
||||
net::WriteRGB(msg, tuning_.primary_color);
|
||||
|
||||
// wheels
|
||||
msg.Write<net::TuningPartIdx>(tuning_.wheels_idx);
|
||||
net::WriteRGB(msg, tuning_.wheel_color);
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include "world.hpp"
|
||||
#include "vehicle_sync.hpp"
|
||||
#include "deform_grid.hpp"
|
||||
#include "vehicle_tuning.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
@ -37,7 +38,7 @@ class Vehicle : public Entity
|
||||
public:
|
||||
using Super = Entity;
|
||||
|
||||
Vehicle(World& world, std::string model_name, const glm::vec3& color);
|
||||
Vehicle(World& world, const VehicleTuning& tuning);
|
||||
|
||||
virtual void Update() override;
|
||||
virtual void SendInitData(Player& player, net::OutMessage& msg) const override;
|
||||
@ -55,9 +56,8 @@ public:
|
||||
|
||||
void SetSteering(bool analog, float value = 0.0f);
|
||||
|
||||
const std::string& GetModelName() const { return model_name_; }
|
||||
const std::string& GetModelName() const { return tuning_.model; }
|
||||
const std::shared_ptr<const assets::VehicleModel>& GetModel() const { return model_; }
|
||||
const glm::vec3& GetColor() const { return color_; }
|
||||
|
||||
virtual ~Vehicle();
|
||||
|
||||
@ -74,10 +74,11 @@ private:
|
||||
void Deform(const glm::vec3& pos, const glm::vec3& deform, float radius);
|
||||
void SendDeformMsg(const net::PositionQ& pos, const net::PositionQ& deform);
|
||||
|
||||
void WriteTuning(net::OutMessage& msg) const;
|
||||
|
||||
private:
|
||||
std::string model_name_;
|
||||
VehicleTuning tuning_;
|
||||
std::shared_ptr<const assets::VehicleModel> model_;
|
||||
glm::vec3 color_;
|
||||
|
||||
collision::MotionState motion_;
|
||||
std::unique_ptr<btRigidBody> body_;
|
||||
|
||||
19
src/game/vehicle_tuning.hpp
Normal file
19
src/game/vehicle_tuning.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace game
|
||||
{
|
||||
|
||||
struct VehicleTuning
|
||||
{
|
||||
std::string model;
|
||||
|
||||
uint32_t primary_color = 0xFFFFFFFF;
|
||||
|
||||
size_t wheels_idx = 0;
|
||||
uint32_t wheel_color = 0xFFFFFFFF;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@ -12,8 +12,7 @@ game::view::VehicleView::VehicleView(WorldView& world, net::InMessage& msg)
|
||||
: EntityView(world, msg)
|
||||
{
|
||||
net::ModelName modelname;
|
||||
glm::vec3 color;
|
||||
if (!msg.Read(modelname) || !net::ReadRGB(msg, color))
|
||||
if (!msg.Read(modelname))
|
||||
throw EntityInitError();
|
||||
|
||||
model_ = assets::CacheManager::GetVehicleModel("data/" + std::string(modelname) + ".veh");
|
||||
@ -28,12 +27,7 @@ game::view::VehicleView::VehicleView(WorldView& world, net::InMessage& msg)
|
||||
wheels_[i].node.parent = &root_;
|
||||
}
|
||||
|
||||
color_ = glm::vec4(color, 1.0f);
|
||||
|
||||
if (!ReadState(&msg))
|
||||
throw EntityInitError();
|
||||
|
||||
if (!ReadDeformSync(msg))
|
||||
if (!ReadTuning(msg) || !ReadState(&msg) || !ReadDeformSync(msg))
|
||||
throw EntityInitError();
|
||||
|
||||
// init the other transform to identical
|
||||
@ -139,13 +133,14 @@ void game::view::VehicleView::Draw(const DrawArgs& args)
|
||||
const auto& wheels = model_->GetWheels();
|
||||
for (size_t i = 0; i < wheels.size(); ++i)
|
||||
{
|
||||
const auto& mesh = *wheels[i].model->GetMesh();
|
||||
const auto& mesh = *wheels_[i].model->GetMesh();
|
||||
|
||||
for (const auto& surface : mesh.surfaces)
|
||||
{
|
||||
gfx::DrawSurfaceCmd cmd;
|
||||
cmd.surface = &surface;
|
||||
cmd.matrices = &wheels_[i].node.matrix;
|
||||
cmd.color = &wheels_[i].color;
|
||||
args.dlist.AddSurface(cmd);
|
||||
}
|
||||
}
|
||||
@ -189,6 +184,35 @@ void game::view::VehicleView::InitMesh()
|
||||
deform_->tex->SetData(deform_->grid.GetData());
|
||||
}
|
||||
|
||||
bool game::view::VehicleView::ReadTuning(net::InMessage& msg)
|
||||
{
|
||||
uint32_t color, wheel_color;
|
||||
net::TuningPartIdx wheel_idx;
|
||||
|
||||
const auto& tuninglist = model_->GetTuningList();
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool game::view::VehicleView::ReadState(net::InMessage* msg)
|
||||
{
|
||||
root_trans_[0] = root_.local;
|
||||
|
||||
@ -13,6 +13,9 @@ namespace game::view
|
||||
|
||||
struct VehicleWheelViewInfo
|
||||
{
|
||||
std::shared_ptr<const assets::Model> model;
|
||||
glm::vec4 color;
|
||||
|
||||
TransformNode node;
|
||||
float steering = 0.0f;
|
||||
float z_offset = 0.0f;
|
||||
@ -43,6 +46,7 @@ public:
|
||||
private:
|
||||
void InitMesh();
|
||||
|
||||
bool ReadTuning(net::InMessage& msg);
|
||||
bool ReadState(net::InMessage* msg);
|
||||
|
||||
bool ReadDeformSync(net::InMessage& msg);
|
||||
|
||||
@ -135,4 +135,8 @@ using NumTexels = uint16_t;
|
||||
|
||||
using Version = uint32_t;
|
||||
|
||||
// tuning
|
||||
|
||||
using TuningPartIdx = uint8_t;
|
||||
|
||||
} // namespace net
|
||||
@ -126,6 +126,25 @@ inline bool ReadRGB(InMessage& msg, glm::vec3& color)
|
||||
return msg.Read<ColorQ>(color.r) && msg.Read<ColorQ>(color.g) && msg.Read<ColorQ>(color.b);
|
||||
}
|
||||
|
||||
// COLOR 24bit
|
||||
inline void WriteRGB(OutMessage& msg, uint32_t color)
|
||||
{
|
||||
msg.Write<uint8_t>(color & 0xFF);
|
||||
msg.Write<uint8_t>((color >> 8) & 0xFF);
|
||||
msg.Write<uint8_t>((color >> 16) & 0xFF);
|
||||
}
|
||||
|
||||
inline bool ReadRGB(InMessage& msg, uint32_t& color)
|
||||
{
|
||||
uint8_t r, g, b;
|
||||
if (!msg.Read(r) || !msg.Read(g) || !msg.Read(b))
|
||||
return false;
|
||||
|
||||
color = (b << 16) | (g << 8) | r;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// DELTA
|
||||
template <std::unsigned_integral T> requires (sizeof(T) == 1)
|
||||
inline void WriteDelta(OutMessage& msg, T previous, T current)
|
||||
|
||||
@ -31,3 +31,13 @@ std::istringstream fs::ReadFileAsStream(const std::string& path)
|
||||
std::string content = ReadFileAsString(path);
|
||||
return std::istringstream(content);
|
||||
}
|
||||
|
||||
bool fs::FileExists(const std::string& path)
|
||||
{
|
||||
SDL_RWops *rw = SDL_RWFromFile(path.c_str(), "rb");
|
||||
if (!rw)
|
||||
return false;
|
||||
|
||||
SDL_RWclose(rw);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
namespace fs
|
||||
{
|
||||
bool FileExists(const std::string& path);
|
||||
std::string ReadFileAsString(const std::string& path);
|
||||
std::istringstream ReadFileAsStream(const std::string& path);
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
#include "files.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
std::string fs::ReadFileAsString(const std::string& path)
|
||||
{
|
||||
@ -22,3 +23,8 @@ std::istringstream fs::ReadFileAsStream(const std::string& path)
|
||||
std::string content = ReadFileAsString(path);
|
||||
return std::istringstream(content);
|
||||
}
|
||||
|
||||
bool fs::FileExists(const std::string& path)
|
||||
{
|
||||
return std::filesystem::exists(path);
|
||||
}
|
||||
@ -1,3 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define FEKAL_VERSION 2026031401
|
||||
#define FEKAL_VERSION 2026032001
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user