Character clothes
This commit is contained in:
parent
8ad81bfb6a
commit
698bcafec0
@ -65,6 +65,14 @@ void game::Character::SendInitData(Player& player, net::OutMessage& msg) const
|
|||||||
{
|
{
|
||||||
Super::SendInitData(player, msg);
|
Super::SendInitData(player, msg);
|
||||||
|
|
||||||
|
// write clothes
|
||||||
|
msg.Write<net::NumClothes>(clothes_.size());
|
||||||
|
for (const auto& clothes : clothes_)
|
||||||
|
{
|
||||||
|
msg.Write(net::ClothesName(clothes.name));
|
||||||
|
net::WriteRGB(msg, clothes.color);
|
||||||
|
}
|
||||||
|
|
||||||
// write state against default
|
// write state against default
|
||||||
static const CharacterSyncState default_state;
|
static const CharacterSyncState default_state;
|
||||||
size_t fields_pos = msg.Reserve<CharacterSyncFieldFlags>();
|
size_t fields_pos = msg.Reserve<CharacterSyncFieldFlags>();
|
||||||
@ -113,6 +121,11 @@ void game::Character::SetPosition(const glm::vec3& position)
|
|||||||
bt_ghost_.setWorldTransform(trans);
|
bt_ghost_.setWorldTransform(trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void game::Character::AddClothes(std::string name, const glm::vec3& color)
|
||||||
|
{
|
||||||
|
clothes_.emplace_back(std::move(name), color);
|
||||||
|
}
|
||||||
|
|
||||||
game::Character::~Character()
|
game::Character::~Character()
|
||||||
{
|
{
|
||||||
btDynamicsWorld& bt_world = world_.GetBtWorld();
|
btDynamicsWorld& bt_world = world_.GetBtWorld();
|
||||||
|
|||||||
@ -33,6 +33,12 @@ struct CharacterInfo
|
|||||||
CapsuleShape shape = CapsuleShape(0.3f, 0.75f);
|
CapsuleShape shape = CapsuleShape(0.3f, 0.75f);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CharacterClothes
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
glm::vec3 color;
|
||||||
|
};
|
||||||
|
|
||||||
class Character : public Entity
|
class Character : public Entity
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -50,6 +56,8 @@ public:
|
|||||||
|
|
||||||
void SetPosition(const glm::vec3& position);
|
void SetPosition(const glm::vec3& position);
|
||||||
|
|
||||||
|
void AddClothes(std::string name, const glm::vec3& color);
|
||||||
|
|
||||||
~Character() override;
|
~Character() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -85,6 +93,8 @@ private:
|
|||||||
|
|
||||||
CharacterSyncState sync_[2];
|
CharacterSyncState sync_[2];
|
||||||
size_t sync_current_ = 0;
|
size_t sync_current_ = 0;
|
||||||
|
|
||||||
|
std::vector<CharacterClothes> clothes_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
@ -233,6 +233,20 @@ void game::OpenWorld::RemoveVehicle(Player& player)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static glm::vec3 GetRandomColor()
|
||||||
|
{
|
||||||
|
glm::vec3 color;
|
||||||
|
// shittiest way to do it
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
net::ColorQ qcol;
|
||||||
|
qcol.value = rand() % 256;
|
||||||
|
color[i] = qcol.Decode();
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
void game::OpenWorld::SpawnCharacter(Player& player)
|
void game::OpenWorld::SpawnCharacter(Player& player)
|
||||||
{
|
{
|
||||||
RemoveCharacter(player);
|
RemoveCharacter(player);
|
||||||
@ -242,6 +256,10 @@ void game::OpenWorld::SpawnCharacter(Player& player)
|
|||||||
character.SetNametag("player (" + std::to_string(character.GetEntNum()) + ")");
|
character.SetNametag("player (" + std::to_string(character.GetEntNum()) + ")");
|
||||||
character.SetPosition({ 100.0f, 100.0f, 5.0f });
|
character.SetPosition({ 100.0f, 100.0f, 5.0f });
|
||||||
|
|
||||||
|
// add clothes
|
||||||
|
character.AddClothes("tshirt", GetRandomColor());
|
||||||
|
character.AddClothes("shorts", GetRandomColor());
|
||||||
|
|
||||||
player.SetCamera(character.GetEntNum());
|
player.SetCamera(character.GetEntNum());
|
||||||
|
|
||||||
player_characters_[&player] = &character;
|
player_characters_[&player] = &character;
|
||||||
@ -531,19 +549,6 @@ static const char* GetRandomCarModel()
|
|||||||
return vehicles[rand() % (sizeof(vehicles) / sizeof(vehicles[0]))];
|
return vehicles[rand() % (sizeof(vehicles) / sizeof(vehicles[0]))];
|
||||||
}
|
}
|
||||||
|
|
||||||
static glm::vec3 GetRandomColor()
|
|
||||||
{
|
|
||||||
glm::vec3 color;
|
|
||||||
// shittiest way to do it
|
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
{
|
|
||||||
net::ColorQ qcol;
|
|
||||||
qcol.value = rand() % 256;
|
|
||||||
color[i] = qcol.Decode();
|
|
||||||
}
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
void game::OpenWorld::SpawnBot()
|
void game::OpenWorld::SpawnBot()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -4,18 +4,37 @@
|
|||||||
#include "net/utils.hpp"
|
#include "net/utils.hpp"
|
||||||
#include "worldview.hpp"
|
#include "worldview.hpp"
|
||||||
|
|
||||||
|
|
||||||
game::view::CharacterView::CharacterView(WorldView& world, net::InMessage& msg) : EntityView(world, msg), ubo_(sk_)
|
game::view::CharacterView::CharacterView(WorldView& world, net::InMessage& msg) : EntityView(world, msg), ubo_(sk_)
|
||||||
{
|
{
|
||||||
|
basemodel_ = assets::CacheManager::GetModel("data/human.mdl");
|
||||||
|
sk_ = SkeletonInstance(basemodel_->GetSkeleton(), &root_);
|
||||||
|
ubo_.Update();
|
||||||
|
ubo_valid_ = true;
|
||||||
|
|
||||||
|
// read clothes
|
||||||
|
net::NumClothes num_clothes = 0;
|
||||||
|
if (!msg.Read(num_clothes))
|
||||||
|
throw EntityInitError();
|
||||||
|
|
||||||
|
for (net::NumClothes i = 0; i < num_clothes; ++i)
|
||||||
|
{
|
||||||
|
net::ClothesName name;
|
||||||
|
glm::vec3 color;
|
||||||
|
|
||||||
|
if (!msg.Read(name) || !net::ReadRGB(msg, color))
|
||||||
|
throw EntityInitError();
|
||||||
|
|
||||||
|
AddClothes(name, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateSurfaceMask();
|
||||||
|
|
||||||
|
// read initial state
|
||||||
if (!ReadState(msg))
|
if (!ReadState(msg))
|
||||||
throw EntityInitError();
|
throw EntityInitError();
|
||||||
|
|
||||||
states_[0] = states_[1]; // lerp from the read state to avoid jump
|
states_[0] = states_[1]; // lerp from the read state to avoid jump
|
||||||
|
|
||||||
basemodel_ = assets::CacheManager::GetModel("data/human.mdl");
|
|
||||||
sk_ = SkeletonInstance(basemodel_->GetSkeleton(), &root_);
|
|
||||||
ubo_.Update();
|
|
||||||
ubo_valid_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool game::view::CharacterView::ProcessMsg(net::EntMsgType type, net::InMessage& msg)
|
bool game::view::CharacterView::ProcessMsg(net::EntMsgType type, net::InMessage& msg)
|
||||||
@ -73,21 +92,39 @@ void game::view::CharacterView::Draw(const DrawArgs& args)
|
|||||||
// args.dlist.AddBeam(p0, p1, 0xFF00EEEE, 0.01f);
|
// args.dlist.AddBeam(p0, p1, 0xFF00EEEE, 0.01f);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// draw human
|
// update skinning matrices
|
||||||
|
|
||||||
if (!ubo_valid_)
|
if (!ubo_valid_)
|
||||||
{
|
{
|
||||||
ubo_.Update();
|
ubo_.Update();
|
||||||
ubo_valid_ = true;
|
ubo_valid_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& mesh = *basemodel_->GetMesh();
|
// draw clothes
|
||||||
|
for (const auto& clothes : clothes_)
|
||||||
|
{
|
||||||
|
const auto& mesh = *clothes.model->GetMesh();
|
||||||
for (const auto& surface : mesh.surfaces)
|
for (const auto& surface : mesh.surfaces)
|
||||||
{
|
{
|
||||||
gfx::DrawSurfaceCmd cmd;
|
gfx::DrawSurfaceCmd cmd;
|
||||||
cmd.surface = &surface;
|
cmd.surface = &surface;
|
||||||
cmd.matrices = &root_.matrix;
|
cmd.matrices = &root_.matrix;
|
||||||
cmd.skinning = &ubo_;
|
cmd.skinning = &ubo_;
|
||||||
|
cmd.color = &clothes.color;
|
||||||
|
args.dlist.AddSurface(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw basemodel
|
||||||
|
const auto& mesh = *basemodel_->GetMesh();
|
||||||
|
for (size_t i = 0; i < mesh.surfaces.size(); ++i)
|
||||||
|
{
|
||||||
|
if (!(surfacemask_ & (1 << i))) // hidden by clothes?
|
||||||
|
continue;
|
||||||
|
|
||||||
|
gfx::DrawSurfaceCmd cmd;
|
||||||
|
cmd.surface = &mesh.surfaces[i];
|
||||||
|
cmd.matrices = &root_.matrix;
|
||||||
|
cmd.skinning = &ubo_;
|
||||||
args.dlist.AddSurface(cmd);
|
args.dlist.AddSurface(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,3 +193,48 @@ bool game::view::CharacterView::ProcessUpdateMsg(net::InMessage& msg)
|
|||||||
{
|
{
|
||||||
return ReadState(msg);
|
return ReadState(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
game::view::CharacterView::SurfaceMask game::view::CharacterView::GetSurfaceMask(const std::string& name)
|
||||||
|
{
|
||||||
|
const auto& surface_names = basemodel_->GetMesh()->surface_names;
|
||||||
|
auto it = surface_names.find(name);
|
||||||
|
if (it != surface_names.end())
|
||||||
|
{
|
||||||
|
return 1 << it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::view::CharacterView::UpdateSurfaceMask()
|
||||||
|
{
|
||||||
|
surfacemask_ = 0xFFFFFFFF;
|
||||||
|
for (const auto& clothes : clothes_)
|
||||||
|
{
|
||||||
|
surfacemask_ &= ~clothes.surfacemask;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::view::CharacterView::AddClothes(const std::string& name, const glm::vec3& color)
|
||||||
|
{
|
||||||
|
CharacterViewClothes c;
|
||||||
|
c.color = glm::vec4(color, 1.0f);
|
||||||
|
|
||||||
|
if (name == "tshirt")
|
||||||
|
{
|
||||||
|
c.model = assets::CacheManager::GetModel("data/tshirt.mdl");
|
||||||
|
c.surfacemask = GetSurfaceMask("upperbody");
|
||||||
|
}
|
||||||
|
else if (name == "shorts")
|
||||||
|
{
|
||||||
|
c.model = assets::CacheManager::GetModel("data/shorts.mdl");
|
||||||
|
c.surfacemask = GetSurfaceMask("upperlegs");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return; // unknown??
|
||||||
|
}
|
||||||
|
|
||||||
|
clothes_.emplace_back(std::move(c));
|
||||||
|
}
|
||||||
|
|||||||
@ -17,10 +17,18 @@ struct CharacterViewState
|
|||||||
float loco_phase = 0.0f;
|
float loco_phase = 0.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CharacterViewClothes
|
||||||
|
{
|
||||||
|
std::shared_ptr<const assets::Model> model;
|
||||||
|
glm::vec4 color = glm::vec4(1.0f);
|
||||||
|
uint32_t surfacemask = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class CharacterView : public EntityView
|
class CharacterView : public EntityView
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Super = EntityView;
|
using Super = EntityView;
|
||||||
|
using SurfaceMask = uint32_t;
|
||||||
|
|
||||||
CharacterView(WorldView& world, net::InMessage& msg);
|
CharacterView(WorldView& world, net::InMessage& msg);
|
||||||
DELETE_COPY_MOVE(CharacterView)
|
DELETE_COPY_MOVE(CharacterView)
|
||||||
@ -33,6 +41,11 @@ private:
|
|||||||
bool ReadState(net::InMessage& msg);
|
bool ReadState(net::InMessage& msg);
|
||||||
bool ProcessUpdateMsg(net::InMessage& msg);
|
bool ProcessUpdateMsg(net::InMessage& msg);
|
||||||
|
|
||||||
|
SurfaceMask GetSurfaceMask(const std::string& name);
|
||||||
|
void UpdateSurfaceMask();
|
||||||
|
|
||||||
|
void AddClothes(const std::string& name, const glm::vec3& color);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float yaw_ = 0.0f;
|
float yaw_ = 0.0f;
|
||||||
|
|
||||||
@ -43,12 +56,13 @@ private:
|
|||||||
|
|
||||||
CharacterAnimState animstate_;
|
CharacterAnimState animstate_;
|
||||||
|
|
||||||
|
uint32_t surfacemask_ = 0xFFFFFFFF;
|
||||||
|
std::vector<CharacterViewClothes> clothes_;
|
||||||
|
|
||||||
// sync
|
// sync
|
||||||
CharacterSyncState sync_;
|
CharacterSyncState sync_;
|
||||||
CharacterViewState states_[2];
|
CharacterViewState states_[2];
|
||||||
float update_time_ = 0.0f;
|
float update_time_ = 0.0f;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -103,4 +103,7 @@ using NameTag = FixedStr<64>;
|
|||||||
using AnimBlendQ = Quantized<uint8_t, 0, 1>;
|
using AnimBlendQ = Quantized<uint8_t, 0, 1>;
|
||||||
using AnimTimeQ = Quantized<uint8_t, 0, 1>;
|
using AnimTimeQ = Quantized<uint8_t, 0, 1>;
|
||||||
|
|
||||||
|
using NumClothes = uint8_t;
|
||||||
|
using ClothesName = FixedStr<32>;
|
||||||
|
|
||||||
} // namespace net
|
} // namespace net
|
||||||
Loading…
x
Reference in New Issue
Block a user