Compare commits

...

7 Commits

29 changed files with 432 additions and 227 deletions

View File

@ -130,6 +130,8 @@ set(SERVER_ONLY_SOURCES
"src/game/destroyed_object.cpp" "src/game/destroyed_object.cpp"
"src/game/drivable_vehicle.hpp" "src/game/drivable_vehicle.hpp"
"src/game/drivable_vehicle.cpp" "src/game/drivable_vehicle.cpp"
"src/game/enterable_world.hpp"
"src/game/enterable_world.cpp"
"src/game/entity.hpp" "src/game/entity.hpp"
"src/game/entity.cpp" "src/game/entity.cpp"
"src/game/game.hpp" "src/game/game.hpp"

View File

@ -1,2 +1,4 @@
# FekalniGtacko # FekalniGtacko
![logo](res/houbymore.png)

BIN
res/houbymore.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

@ -95,7 +95,7 @@ int assets::MapLoader::GetPercent() const
return 10; return 10;
case ML_LOAD_MODELS: case ML_LOAD_MODELS:
return 60 + models_.size() * 30 / model_names_.size(); return 60 + (model_names_.size() > 0 ? (models_.size() * 30 / model_names_.size()) : 30);
case ML_STRUCTS: case ML_STRUCTS:
return 90; return 90;

View File

@ -4,10 +4,10 @@
#include "utils/math.hpp" #include "utils/math.hpp"
#include "world.hpp" #include "world.hpp"
game::Character::Character(World& world, const CharacterInfo& info) game::Character::Character(World& world, const CharacterTuning& tuning)
: Super(world, net::ET_CHARACTER), shape_(info.shape), bt_shape_(shape_.radius, shape_.height) : Super(world, net::ET_CHARACTER), tuning_(tuning), bt_shape_(tuning_.shape.radius, tuning_.shape.height)
{ {
z_offset_ = shape_.height * 0.5f + shape_.radius - 0.05f; z_offset_ = tuning_.shape.height * 0.5f + tuning_.shape.radius - 0.05f;
sk_ = SkeletonInstance(assets::CacheManager::GetSkeleton("data/human.sk"), &root_); sk_ = SkeletonInstance(assets::CacheManager::GetSkeleton("data/human.sk"), &root_);
animstate_.idle_anim_idx = GetAnim("idle"); animstate_.idle_anim_idx = GetAnim("idle");
@ -53,8 +53,8 @@ void game::Character::SendInitData(Player& player, net::OutMessage& msg) const
Super::SendInitData(player, msg); Super::SendInitData(player, msg);
// write clothes // write clothes
msg.Write<net::NumClothes>(clothes_.size()); msg.Write<net::NumClothes>(tuning_.clothes.size());
for (const auto& clothes : clothes_) for (const auto& clothes : tuning_.clothes)
{ {
msg.Write(net::ClothesName(clothes.name)); msg.Write(net::ClothesName(clothes.name));
net::WriteRGB(msg, clothes.color); net::WriteRGB(msg, clothes.color);
@ -120,11 +120,6 @@ void game::Character::SetPosition(const glm::vec3& position)
SyncControllerTransform(); SyncControllerTransform();
} }
void game::Character::AddClothes(std::string name, const glm::vec3& color)
{
clothes_.emplace_back(std::move(name), color);
}
void game::Character::SetMainAnim(const std::string& anim_name) void game::Character::SetMainAnim(const std::string& anim_name)
{ {
animstate_.idle_anim_idx = GetAnim(anim_name); animstate_.idle_anim_idx = GetAnim(anim_name);

View File

@ -6,6 +6,7 @@
#include "character_anim_state.hpp" #include "character_anim_state.hpp"
#include "character_sync.hpp" #include "character_sync.hpp"
#include "entity.hpp" #include "entity.hpp"
#include "character_tuning.hpp"
namespace game namespace game
{ {
@ -22,25 +23,6 @@ enum CharacterInputType
CIN_SPRINT, CIN_SPRINT,
}; };
struct CapsuleShape
{
float radius;
float height;
CapsuleShape(float radius, float height) : radius(radius), height(height) {}
};
struct CharacterInfo
{
CapsuleShape shape = CapsuleShape(0.3f, 0.75f);
};
struct CharacterClothes
{
std::string name;
glm::vec3 color;
};
class CharacterPhysicsController class CharacterPhysicsController
{ {
public: public:
@ -65,11 +47,13 @@ class Character : public Entity
public: public:
using Super = Entity; using Super = Entity;
Character(World& world, const CharacterInfo& info); Character(World& world, const CharacterTuning& tuning);
virtual void Update() override; virtual void Update() override;
virtual void SendInitData(Player& player, net::OutMessage& msg) const override; virtual void SendInitData(Player& player, net::OutMessage& msg) const override;
const CharacterTuning& GetTuning() const { return tuning_; }
void EnablePhysics(bool enable); void EnablePhysics(bool enable);
void SetInput(CharacterInputType type, bool enable); void SetInput(CharacterInputType type, bool enable);
@ -80,8 +64,6 @@ public:
void SetPosition(const glm::vec3& position); void SetPosition(const glm::vec3& position);
void AddClothes(std::string name, const glm::vec3& color);
void SetMainAnim(const std::string& anim_name); void SetMainAnim(const std::string& anim_name);
~Character() override = default; ~Character() override = default;
@ -100,7 +82,7 @@ private:
assets::AnimIdx GetAnim(const std::string& name) const; assets::AnimIdx GetAnim(const std::string& name) const;
private: private:
CapsuleShape shape_; CharacterTuning tuning_;
// glm::vec3 position_ = glm::vec3(0.0f); // glm::vec3 position_ = glm::vec3(0.0f);
// glm::vec3 velocity_ = glm::vec3(0.0f); // glm::vec3 velocity_ = glm::vec3(0.0f);
@ -121,8 +103,6 @@ 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

View File

@ -0,0 +1,30 @@
#pragma once
#include <string>
#include <vector>
namespace game
{
struct CharacterShape
{
float radius;
float height;
CharacterShape(float radius, float height) : radius(radius), height(height) {}
};
struct CharacterConfigClothes
{
std::string name;
uint32_t color = 0xFFFFFF;
};
struct CharacterTuning
{
CharacterShape shape = CharacterShape(0.3f, 0.75f);
std::vector<CharacterConfigClothes> clothes;
};
}

View File

@ -1,7 +1,7 @@
#include "controllable_character.hpp" #include "controllable_character.hpp"
#include "drivable_vehicle.hpp" #include "drivable_vehicle.hpp"
game::ControllableCharacter::ControllableCharacter(World& world) : Character(world, CharacterInfo{}) {} game::ControllableCharacter::ControllableCharacter(World& world, const CharacterTuning& tuning) : Character(world, tuning) {}
void game::ControllableCharacter::SetVehicle(DrivableVehicle* vehicle, uint32_t seat) void game::ControllableCharacter::SetVehicle(DrivableVehicle* vehicle, uint32_t seat)
{ {

View File

@ -12,7 +12,7 @@ class ControllableCharacter : public Character
public: public:
using Super = Character; using Super = Character;
ControllableCharacter(World& world); ControllableCharacter(World& world, const CharacterTuning& tuning);
void SetVehicle(DrivableVehicle* vehicle, uint32_t seat); void SetVehicle(DrivableVehicle* vehicle, uint32_t seat);

View File

@ -22,6 +22,9 @@ public:
bool SetPassenger(uint32_t seat_idx, ControllableCharacter* character); bool SetPassenger(uint32_t seat_idx, ControllableCharacter* character);
size_t GetNumSeats() const { return seats_.size(); }
ControllableCharacter* GetPassenger(size_t idx) const { return seats_[idx].occupant; }
~DrivableVehicle() override; ~DrivableVehicle() override;
private: private:

View File

@ -0,0 +1,131 @@
#include "enterable_world.hpp"
#include "player_character.hpp"
#include "drivable_vehicle.hpp"
game::EnterableWorld::EnterableWorld(std::string mapname) : World(std::move(mapname)) {}
game::PlayerCharacter& game::EnterableWorld::InsertPlayer(Player& player, const CharacterTuning& tuning, const glm::vec3& pos, float yaw)
{
return CreatePlayerCharacter(player, tuning, pos, yaw);
}
void game::EnterableWorld::PlayerInput(Player& player, PlayerInputType type, bool enabled)
{
auto it = player_characters_.find(&player);
if (it == player_characters_.end())
return;
auto character = it->second;
switch (type)
{
// case IN_DEBUG1:
// if (enabled)
// {
// if (character->GetVehicle())
// character->GetVehicle()->SetPosition({100.0f, 100.0f, 5.0f});
// else
// character->SetPosition({100.0f, 100.0f, 5.0f});
// }
// break;
default:
character->ProcessInput(type, enabled);
break;
}
}
void game::EnterableWorld::PlayerViewAnglesChanged(Player& player, float yaw, float pitch)
{
auto it = player_characters_.find(&player);
if (it == player_characters_.end())
return;
auto character = it->second;
character->SetForwardYaw(yaw);
}
void game::EnterableWorld::RemovePlayer(Player& player)
{
RemovePlayerCharacter(player);
}
game::PlayerCharacter& game::EnterableWorld::MovePlayerToWorld(Player& player, EnterableWorld& new_world, const glm::vec3& pos, float yaw)
{
auto old_character = player_characters_.at(&player);
auto& tuning = old_character->GetTuning();
RemovePlayer(player);
player.SetWorld(&new_world);
auto& new_character = new_world.InsertPlayer(player, tuning, pos, yaw);
return new_character;
}
void game::EnterableWorld::MoveVehicleToWorld(DrivableVehicle& vehicle, EnterableWorld& new_world, const glm::vec3& pos,
float yaw)
{
if (&vehicle.GetWorld() != this)
throw std::runtime_error("Attempt to move vehicle from other world");
auto& tuning = vehicle.GetTuning();
auto& new_vehicle = new_world.Spawn<DrivableVehicle>(tuning);
new_vehicle.SetPosition(pos);
// TODO: yaw
// move passengers
size_t num_seats = vehicle.GetNumSeats();
for (size_t i = 0; i < num_seats; ++i)
{
auto passenger = vehicle.GetPassenger(i);
if (!passenger)
continue; // empty seat
auto player_passenger = dynamic_cast<PlayerCharacter*>(passenger);
if (!player_passenger)
continue; // not player but npc, will be ejected automatically upon vehicle deletion
auto player = player_passenger->GetPlayer();
if (!player)
continue; // moved already or sth
auto& new_character = MovePlayerToWorld(*player, new_world, glm::vec3(0.0f), 0.0f);
new_character.SetVehicle(&new_vehicle, i);
}
vehicle.Remove();
}
game::PlayerCharacter* game::EnterableWorld::GetPlayerCharacter(Player& player)
{
auto it = player_characters_.find(&player);
if (it == player_characters_.end())
return nullptr;
return it->second;
}
game::PlayerCharacter& game::EnterableWorld::CreatePlayerCharacter(Player& player, const CharacterTuning& tuning, const glm::vec3& position, float yaw)
{
RemovePlayerCharacter(player);
auto& character = Spawn<PlayerCharacter>(player, tuning);
character.SetPosition(position);
character.SetYaw(yaw);
player_characters_[&player] = &character;
return character;
}
void game::EnterableWorld::RemovePlayerCharacter(Player& player)
{
auto character = GetPlayerCharacter(player);
if (character)
{
character->DetachFromPlayer();
character->Remove();
}
}

View File

@ -0,0 +1,41 @@
#pragma once
#include "world.hpp"
namespace game
{
class Player;
class PlayerCharacter;
class CharacterTuning;
class DrivableVehicle;
class EnterableWorld : public World
{
public:
EnterableWorld(std::string mapname);
// events
virtual PlayerCharacter& InsertPlayer(Player& player, const CharacterTuning& tuning, const glm::vec3& pos, float yaw);
virtual void PlayerInput(Player& player, PlayerInputType type, bool enabled);
virtual void PlayerViewAnglesChanged(Player& player, float yaw, float pitch);
virtual void RemovePlayer(Player& player);
// moves
PlayerCharacter& MovePlayerToWorld(Player& player, EnterableWorld& new_world, const glm::vec3& pos, float yaw);
void MoveVehicleToWorld(DrivableVehicle& vehicle, EnterableWorld& new_world, const glm::vec3& pos, float yaw);
PlayerCharacter* GetPlayerCharacter(Player& player);
private:
PlayerCharacter& CreatePlayerCharacter(Player& player, const CharacterTuning& tuning, const glm::vec3& position, float yaw);
void RemovePlayerCharacter(Player& player);
private:
std::map<Player*, PlayerCharacter*> player_characters_;
};
}

View File

@ -24,6 +24,8 @@ public:
net::EntNum GetEntNum() const { return entnum_; } net::EntNum GetEntNum() const { return entnum_; }
net::EntType GetViewType() const { return viewtype_; } net::EntType GetViewType() const { return viewtype_; }
World& GetWorld() const { return world_; }
virtual void SendInitData(Player& player, net::OutMessage& msg) const; virtual void SendInitData(Player& player, net::OutMessage& msg) const;
virtual void Update(); virtual void Update();

View File

@ -1,47 +1,147 @@
#include "game.hpp" #include "game.hpp"
#include "player.hpp"
#include "openworld.hpp" #include "openworld.hpp"
#include "player.hpp"
#include "player_character.hpp"
static constexpr glm::vec3 openworld_spawn(100.0f, 100.0f, 1.0f);
static constexpr glm::vec3 test_spawn(0.0f, 0.0f, 1.0f);
static uint32_t GetRandomColor24()
{
uint8_t r, g, b;
r = rand() % 256;
g = rand() % 256;
b = rand() % 256;
return (b << 16) | (g << 8) | r;
}
game::Game::Game() game::Game::Game()
{ {
default_world_ = std::make_shared<OpenWorld>(); openworld_ = std::make_shared<OpenWorld>();
all_worlds_.push_back(openworld_.get());
testworld_ = std::make_shared<EnterableWorld>("testarena");
all_worlds_.push_back(testworld_.get());
} }
void game::Game::Update() void game::Game::Update()
{ {
default_world_->Update(40); for (auto world : all_worlds_)
{
world->Update(40);
}
} }
void game::Game::FinishFrame() void game::Game::FinishFrame()
{ {
default_world_->FinishFrame(); for (auto world : all_worlds_)
{
world->FinishFrame();
}
} }
void game::Game::PlayerJoined(Player& player) void game::Game::PlayerJoined(Player& player)
{ {
player.SetWorld(default_world_);
players_.insert(&player);
BroadcastChat(player.GetName() + "^r se připoojil jupí jupí jupííí"); BroadcastChat(player.GetName() + "^r se připoojil jupí jupí jupííí");
players_.insert({&player, PlayerGameInfo(player)});
auto& player_info = players_.at(&player);
player_info.world = openworld_.get();
player.SetWorld(openworld_.get());
CharacterTuning tuning{};
tuning.clothes.push_back({"tshirt", GetRandomColor24()});
tuning.clothes.push_back({"shorts", GetRandomColor24()});
openworld_->InsertPlayer(player, tuning, openworld_spawn, 0.0f);
}
void game::Game::PlayerViewAnglesChanged(Player& player, float yaw, float pitch)
{
auto world = FindPlayerWorld(player);
if (world)
world->PlayerViewAnglesChanged(player, yaw, pitch);
}
void game::Game::PlayerInput(Player& player, PlayerInputType type, bool enabled)
{
switch (type)
{
case IN_DEBUG2: {
if (!enabled)
return;
auto& player_info = players_.at(&player);
if (player_info.world == openworld_.get())
{
MovePlayerToWorld(player_info, testworld_.get(), test_spawn, 0.0f, true);
}
else
{
MovePlayerToWorld(player_info, openworld_.get(), openworld_spawn, 0.0f, true);
}
break;
}
default: {
auto world = FindPlayerWorld(player);
if (world)
world->PlayerInput(player, type, enabled);
break;
}
}
} }
void game::Game::PlayerLeft(Player& player) void game::Game::PlayerLeft(Player& player)
{ {
players_.erase(&player); auto world = FindPlayerWorld(player);
BroadcastChat(player.GetName() + "^r se vodpojil zmrd"); if (world)
} world->RemovePlayer(player);
bool game::Game::PlayerInput(Player& player, PlayerInputType type, bool enabled) players_.erase(&player);
{
return false; // not handled here BroadcastChat(player.GetName() + "^r se vodpojil zmrd");
} }
void game::Game::BroadcastChat(const std::string& text) void game::Game::BroadcastChat(const std::string& text)
{ {
for (auto player : players_) for (auto& [player, info] : players_)
{ {
player->SendChat(text); player->SendChat(text);
} }
} }
void game::Game::MovePlayerToWorld(PlayerGameInfo& player_info, EnterableWorld* new_world, const glm::vec3& pos,
float yaw, bool with_vehicle)
{
auto& player = player_info.player;
auto& world = *player_info.world;
DrivableVehicle* vehicle = nullptr;
if (with_vehicle)
{
auto character = world.GetPlayerCharacter(player);
vehicle = character->GetVehicle();
}
if (vehicle)
world.MoveVehicleToWorld(*vehicle, *new_world, pos, yaw);
else
world.MovePlayerToWorld(player, *new_world, pos, yaw);
player_info.world = new_world;
}
game::EnterableWorld* game::Game::FindPlayerWorld(Player& player) const
{
auto it = players_.find(&player);
if (it == players_.end())
return nullptr;
return it->second.world;
}

View File

@ -1,15 +1,23 @@
#pragma once #pragma once
#include <map> #include <map>
#include <set>
#include "world.hpp" #include "enterable_world.hpp"
#include "openworld.hpp"
namespace game namespace game
{ {
class Player; class Player;
struct PlayerGameInfo
{
Player& player;
EnterableWorld* world = nullptr;
PlayerGameInfo(Player& player) : player(player) {}
};
class Game class Game
{ {
public: public:
@ -19,15 +27,23 @@ public:
void FinishFrame(); void FinishFrame();
void PlayerJoined(Player& player); void PlayerJoined(Player& player);
void PlayerViewAnglesChanged(Player& player, float yaw, float pitch);
void PlayerInput(Player& player, PlayerInputType type, bool enabled);
void PlayerLeft(Player& player); void PlayerLeft(Player& player);
bool PlayerInput(Player& player, PlayerInputType type, bool enabled);
private: private:
void BroadcastChat(const std::string& text); void BroadcastChat(const std::string& text);
void MovePlayerToWorld(PlayerGameInfo& player_info, EnterableWorld* new_world, const glm::vec3& pos, float yaw, bool with_vehicle = false);
EnterableWorld* FindPlayerWorld(Player& player) const;
private: private:
std::shared_ptr<World> default_world_; std::shared_ptr<OpenWorld> openworld_;
std::set<Player*> players_; std::shared_ptr<EnterableWorld> testworld_;
std::vector<World*> all_worlds_; // for common update etc.
std::map<Player*, PlayerGameInfo> players_;
}; };

View File

@ -5,7 +5,7 @@
#include <array> #include <array>
#include <iostream> #include <iostream>
game::NpcCharacter::NpcCharacter(World& world) : Super(world) { game::NpcCharacter::NpcCharacter(World& world, const CharacterTuning& tuning) : Super(world, tuning) {
VehicleChanged(); VehicleChanged();
} }

View File

@ -13,7 +13,7 @@ class NpcCharacter : public ControllableCharacter
public: public:
using Super = ControllableCharacter; using Super = ControllableCharacter;
NpcCharacter(World& world); NpcCharacter(World& world, const CharacterTuning& tuning);
virtual void VehicleChanged() override; virtual void VehicleChanged() override;

View File

@ -45,10 +45,8 @@ static uint32_t GetRandomColor24()
return (b << 16) | (g << 8) | r; return (b << 16) | (g << 8) | r;
} }
game::OpenWorld::OpenWorld() : World("openworld") game::OpenWorld::OpenWorld() : EnterableWorld("openworld")
{ {
srand(time(NULL));
// spawn bots // spawn bots
for (size_t i = 0; i < 100; ++i) for (size_t i = 0; i < 100; ++i)
{ {
@ -81,97 +79,6 @@ game::OpenWorld::OpenWorld() : World("openworld")
} }
void game::OpenWorld::Update(int64_t delta_time)
{
World::Update(delta_time);
}
void game::OpenWorld::PlayerJoined(Player& player)
{
CreatePlayerCharacter(player);
}
void game::OpenWorld::PlayerInput(Player& player, PlayerInputType type, bool enabled)
{
auto character = player_characters_.at(&player);
switch (type)
{
case IN_DEBUG1:
if (enabled)
{
if (character->GetVehicle())
character->GetVehicle()->SetPosition({100.0f, 100.0f, 5.0f});
else
character->SetPosition({100.0f, 100.0f, 5.0f});
}
break;
case IN_DEBUG2:
if (enabled)
CreatePlayerCharacter(player);
break;
default:
character->ProcessInput(type, enabled);
break;
}
}
void game::OpenWorld::PlayerViewAnglesChanged(Player& player, float yaw, float pitch)
{
auto character = player_characters_.at(&player);
character->SetForwardYaw(yaw);
}
void game::OpenWorld::PlayerLeft(Player& player)
{
RemovePlayerCharacter(player);
}
void game::OpenWorld::DestructibleDestroyed(net::ObjNum num, std::unique_ptr<MapObjectCollision> col)
{
auto& destroyed_obj = Spawn<DestroyedObject>(std::move(col));
Schedule(120000, [this, num] {
RespawnObj(num);
});
}
template <class T, typename... TArgs>
static T& SpawnRandomCharacter(game::OpenWorld& world, TArgs&&... args)
{
auto& character = world.Spawn<T>(std::forward<TArgs>(args)...);
// add clothes
character.AddClothes("tshirt", GetRandomColor());
character.AddClothes("shorts", GetRandomColor());
return character;
}
void game::OpenWorld::CreatePlayerCharacter(Player& player)
{
RemovePlayerCharacter(player);
auto& character = SpawnRandomCharacter<PlayerCharacter>(*this, player);
// character.SetNametag("player (" + std::to_string(character.GetEntNum()) + ")");
character.SetPosition({100.0f, 100.0f, 5.0f});
player_characters_[&player] = &character;
}
void game::OpenWorld::RemovePlayerCharacter(Player& player)
{
auto it = player_characters_.find(&player);
if (it != player_characters_.end())
{
it->second->Remove();
player_characters_.erase(it);
}
}
game::DrivableVehicle& game::OpenWorld::SpawnRandomVehicle() game::DrivableVehicle& game::OpenWorld::SpawnRandomVehicle()
{ {
game::VehicleTuning tuning; game::VehicleTuning tuning;
@ -198,6 +105,10 @@ void game::OpenWorld::SpawnBot()
auto& vehicle = SpawnRandomVehicle(); auto& vehicle = SpawnRandomVehicle();
vehicle.SetPosition(roads->nodes[start_node].position + glm::vec3{0.0f, 0.0f, 5.0f}); vehicle.SetPosition(roads->nodes[start_node].position + glm::vec3{0.0f, 0.0f, 5.0f});
auto& driver = SpawnRandomCharacter<NpcCharacter>(*this); CharacterTuning npc_tuning;
npc_tuning.clothes.push_back({ "tshirt", GetRandomColor24() });
npc_tuning.clothes.push_back({ "shorts", GetRandomColor24() });
auto& driver = Spawn<NpcCharacter>(npc_tuning);
driver.SetVehicle(&vehicle, 0); driver.SetVehicle(&vehicle, 0);
} }

View File

@ -1,42 +1,21 @@
#pragma once #pragma once
#include "world.hpp" #include "enterable_world.hpp"
#include "vehicle.hpp" #include "npc_character.hpp"
#include "character.hpp"
#include "usable.hpp"
#include "drivable_vehicle.hpp"
#include <optional>
namespace game namespace game
{ {
class PlayerCharacter; class OpenWorld : public EnterableWorld
class NpcCharacter;
class OpenWorld : public World
{ {
public: public:
OpenWorld(); OpenWorld();
virtual void Update(int64_t delta_time) override; private:
virtual void PlayerJoined(Player& player) override;
virtual void PlayerInput(Player& player, PlayerInputType type, bool enabled) override;
virtual void PlayerViewAnglesChanged(Player& player, float yaw, float pitch) override;
virtual void PlayerLeft(Player& player) override;
virtual void DestructibleDestroyed(net::ObjNum num, std::unique_ptr<MapObjectCollision> col) override;
private:
void CreatePlayerCharacter(Player& player);
void RemovePlayerCharacter(Player& player);
game::DrivableVehicle& SpawnRandomVehicle(); game::DrivableVehicle& SpawnRandomVehicle();
void SpawnBot(); void SpawnBot();
private: private:
std::map<Player*, PlayerCharacter*> player_characters_;
std::vector<NpcCharacter*> npcs_; std::vector<NpcCharacter*> npcs_;
}; };

View File

@ -6,6 +6,7 @@
#include <glm/gtx/norm.hpp> #include <glm/gtx/norm.hpp>
#include "world.hpp" #include "world.hpp"
#include "game.hpp"
game::Player::Player(Game& game, std::string name) : game_(game), name_(std::move(name)) game::Player::Player(Game& game, std::string name) : game_(game), name_(std::move(name))
{ {
@ -29,11 +30,13 @@ bool game::Player::ProcessMsg(net::MessageType type, net::InMessage& msg)
void game::Player::Update() void game::Player::Update()
{ {
if (world_.get() != known_world_) if (world_ != known_world_)
{ {
SendWorldMsg(); SendWorldMsg();
known_world_ = world_.get(); known_world_ = world_;
known_ents_.clear(); known_ents_.clear();
return; // send updates next frame
} }
if (world_) if (world_)
@ -43,18 +46,12 @@ void game::Player::Update()
} }
} }
void game::Player::SetWorld(std::shared_ptr<World> world) void game::Player::SetWorld(World* world)
{ {
if (world == world_) if (world == world_)
return; return;
if (world_) world_ = world;
world_->PlayerLeft(*this);
world_ = std::move(world);
if (world_)
world_->PlayerJoined(*this);
} }
void game::Player::SetCamera(net::EntNum entnum) void game::Player::SetCamera(net::EntNum entnum)
@ -74,7 +71,6 @@ void game::Player::SendChat(const std::string& text)
game::Player::~Player() game::Player::~Player()
{ {
SetWorld(nullptr);
game_.PlayerLeft(*this); game_.PlayerLeft(*this);
} }
@ -247,9 +243,7 @@ bool game::Player::ProcessViewAnglesMsg(net::InMessage& msg)
view_yaw_ = yaw_q.Decode(); view_yaw_ = yaw_q.Decode();
view_pitch_ = pitch_q.Decode(); view_pitch_ = pitch_q.Decode();
if (world_) game_.PlayerViewAnglesChanged(*this, view_yaw_, view_pitch_);
world_->PlayerViewAnglesChanged(*this, view_yaw_, view_pitch_);
return true; return true;
} }
@ -260,10 +254,6 @@ void game::Player::Input(PlayerInputType type, bool enabled)
else else
in_ &= ~(1 << type); in_ &= ~(1 << type);
if (!game_.PlayerInput(*this, type, enabled)) game_.PlayerInput(*this, type, enabled);
{
if (world_)
world_->PlayerInput(*this, type, enabled);
}
} }

View File

@ -1,20 +1,23 @@
#pragma once #pragma once
#include <set> #include <set>
#include <memory>
#include <glm/glm.hpp>
#include "net/defs.hpp" #include "net/defs.hpp"
#include "net/inmessage.hpp" #include "net/inmessage.hpp"
#include "net/msg_producer.hpp" #include "net/msg_producer.hpp"
#include "utils/defs.hpp"
#include "player_input.hpp" #include "player_input.hpp"
#include "game.hpp"
namespace game namespace game
{ {
class Game;
class World; class World;
class Entity; class Entity;
class Vehicle;
class Player : public net::MsgProducer class Player : public net::MsgProducer
{ {
@ -25,7 +28,7 @@ public:
bool ProcessMsg(net::MessageType type, net::InMessage& msg); bool ProcessMsg(net::MessageType type, net::InMessage& msg);
void Update(); void Update();
void SetWorld(std::shared_ptr<World> world); void SetWorld(World* world);
void SetCamera(net::EntNum entnum); void SetCamera(net::EntNum entnum);
void SendChat(const std::string& text); void SendChat(const std::string& text);
@ -60,7 +63,7 @@ private:
Game& game_; Game& game_;
std::string name_; std::string name_;
std::shared_ptr<World> world_ = nullptr; World* world_ = nullptr;
World* known_world_ = nullptr; World* known_world_ = nullptr;
std::set<net::EntNum> known_ents_; std::set<net::EntNum> known_ents_;

View File

@ -1,7 +1,7 @@
#include "player_character.hpp" #include "player_character.hpp"
#include "openworld.hpp" #include "world.hpp"
game::PlayerCharacter::PlayerCharacter(World& world, Player& player) : Super(world), player_(player) game::PlayerCharacter::PlayerCharacter(World& world, Player& player, const CharacterTuning& tuning) : Super(world, tuning), player_(&player)
{ {
EnablePhysics(true); EnablePhysics(true);
VehicleChanged(); VehicleChanged();
@ -18,13 +18,16 @@ void game::PlayerCharacter::Update()
void game::PlayerCharacter::VehicleChanged() void game::PlayerCharacter::VehicleChanged()
{ {
if (!player_)
return;
if (vehicle_) if (vehicle_)
{ {
player_.SetCamera(vehicle_->GetEntNum()); player_->SetCamera(vehicle_->GetEntNum());
} }
else else
{ {
player_.SetCamera(GetEntNum()); player_->SetCamera(GetEntNum());
} }
UpdateInputs(); UpdateInputs();
@ -59,9 +62,14 @@ void game::PlayerCharacter::ProcessInput(PlayerInputType type, bool enabled)
} }
} }
void game::PlayerCharacter::DetachFromPlayer()
{
player_ = nullptr;
}
void game::PlayerCharacter::UpdateInputs() void game::PlayerCharacter::UpdateInputs()
{ {
auto in = player_.GetInput(); auto in = player_ ? player_->GetInput() : 0;
CharacterInputFlags c_in = 0; CharacterInputFlags c_in = 0;
VehicleInputFlags v_in = 0; VehicleInputFlags v_in = 0;

View File

@ -2,18 +2,17 @@
#include "drivable_vehicle.hpp" #include "drivable_vehicle.hpp"
#include "player.hpp" #include "player.hpp"
#include "world.hpp"
namespace game namespace game
{ {
class OpenWorld;
class PlayerCharacter : public ControllableCharacter class PlayerCharacter : public ControllableCharacter
{ {
public: public:
using Super = ControllableCharacter; using Super = ControllableCharacter;
PlayerCharacter(World& world, Player& player); PlayerCharacter(World& world, Player& player, const CharacterTuning& tuning);
virtual void Update() override; virtual void Update() override;
@ -21,12 +20,16 @@ public:
void ProcessInput(PlayerInputType type, bool enabled); void ProcessInput(PlayerInputType type, bool enabled);
void DetachFromPlayer();
Player* GetPlayer() const { return player_; }
private: private:
void UpdateInputs(); void UpdateInputs();
void UpdateUseTarget(); void UpdateUseTarget();
private: private:
Player& player_; Player* player_;
}; };

View File

@ -58,6 +58,7 @@ 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(); virtual ~Vehicle();

View File

@ -6,6 +6,7 @@
#include "assets/cache.hpp" #include "assets/cache.hpp"
#include "utils/allocnum.hpp" #include "utils/allocnum.hpp"
#include "collision/object_info.hpp" #include "collision/object_info.hpp"
#include "destroyed_object.hpp"
game::World::World(std::string mapname) : Scheduler(time_ms_), map_(*this, std::move(mapname)) game::World::World(std::string mapname) : Scheduler(time_ms_), map_(*this, std::move(mapname))
{ {
@ -78,6 +79,15 @@ void game::World::FinishFrame()
} }
void game::World::DestructibleDestroyed(net::ObjNum num, std::unique_ptr<MapObjectCollision> col)
{
auto& destroyed_obj = Spawn<DestroyedObject>(std::move(col));
Schedule(120000, [this, num] {
RespawnObj(num);
});
}
game::Entity* game::World::GetEntity(net::EntNum entnum) game::Entity* game::World::GetEntity(net::EntNum entnum)
{ {
auto it = ents_.find(entnum); auto it = ents_.find(entnum);

View File

@ -37,13 +37,7 @@ public:
virtual void Update(int64_t delta_time); virtual void Update(int64_t delta_time);
void FinishFrame(); void FinishFrame();
// events virtual void DestructibleDestroyed(net::ObjNum num, std::unique_ptr<MapObjectCollision> col);
virtual void PlayerJoined(Player& player) {}
virtual void PlayerInput(Player& player, PlayerInputType type, bool enabled) {}
virtual void PlayerViewAnglesChanged(Player& player, float yaw, float pitch) {}
virtual void PlayerLeft(Player& player) {}
virtual void DestructibleDestroyed(net::ObjNum num, std::unique_ptr<MapObjectCollision> col) {}
Entity* GetEntity(net::EntNum entnum); Entity* GetEntity(net::EntNum entnum);

View File

@ -9,12 +9,14 @@
#include "draw_args.hpp" #include "draw_args.hpp"
game::view::WorldView::WorldView(ClientSession& session, net::InMessage& msg) : game::view::WorldView::WorldView(ClientSession& session, net::InMessage& msg) :
session_(session), audiomaster_(session_.GetAudioMaster()), map_("openworld") session_(session), audiomaster_(session_.GetAudioMaster())
{ {
net::MapName mapname; net::MapName mapname;
if (!msg.Read(mapname)) if (!msg.Read(mapname))
throw EntityInitError(); throw EntityInitError();
map_ = std::make_unique<MapInstanceView>(std::string(mapname));
// init destroyed objs // init destroyed objs
net::ObjCount objcount; net::ObjCount objcount;
if (!msg.Read(objcount)) if (!msg.Read(objcount))
@ -26,7 +28,7 @@ game::view::WorldView::WorldView(ClientSession& session, net::InMessage& msg) :
if (!msg.Read(objnum)) if (!msg.Read(objnum))
throw EntityInitError(); throw EntityInitError();
map_.EnableObj(objnum, false); map_->EnableObj(objnum, false);
} }
// cache common snds and stuff // cache common snds and stuff
@ -69,8 +71,8 @@ void game::view::WorldView::Update(const UpdateInfo& info)
{ {
time_ = info.time; time_ = info.time;
if (!map_.IsLoaded()) if (!map_->IsLoaded())
map_.LoadNext(); map_->LoadNext();
for (const auto& [entnum, ent] : ents_) for (const auto& [entnum, ent] : ents_)
{ {
@ -80,7 +82,7 @@ void game::view::WorldView::Update(const UpdateInfo& info)
void game::view::WorldView::Draw(const DrawArgs& args) const void game::view::WorldView::Draw(const DrawArgs& args) const
{ {
if (!map_.IsLoaded()) if (!map_->IsLoaded())
{ {
DrawLoadingScreen(args); DrawLoadingScreen(args);
return; return;
@ -88,7 +90,7 @@ void game::view::WorldView::Draw(const DrawArgs& args) const
args.env.clear_color = glm::vec3(0.5f, 0.7f, 1.0f); args.env.clear_color = glm::vec3(0.5f, 0.7f, 1.0f);
map_.Draw(args); map_->Draw(args);
for (const auto& [entnum, ent] : ents_) for (const auto& [entnum, ent] : ents_)
{ {
@ -137,7 +139,7 @@ void game::view::WorldView::DrawLoadingScreen(const DrawArgs& args) const
glm::vec2 size(400.0f, 15.0f); glm::vec2 size(400.0f, 15.0f);
glm::vec2 pos(margin, args.screen_size.y - margin - size.y); glm::vec2 pos(margin, args.screen_size.y - margin - size.y);
int loaded_percent = map_.GetLoadingPercent(); int loaded_percent = map_->GetLoadingPercent();
float loaded = static_cast<float>(loaded_percent) * 0.01f; float loaded = static_cast<float>(loaded_percent) * 0.01f;
args.gui.DrawRect(pos, pos + size, 0x77FFFFFF); args.gui.DrawRect(pos, pos + size, 0x77FFFFFF);
@ -267,7 +269,7 @@ bool game::view::WorldView::ProcessObjDestroyOrRespawnMsg(net::InMessage& msg, b
if (!msg.Read(objnum)) if (!msg.Read(objnum))
return false; return false;
map_.EnableObj(objnum, enable); map_->EnableObj(objnum, enable);
return true; return true;
} }

View File

@ -48,7 +48,7 @@ private:
private: private:
ClientSession& session_; ClientSession& session_;
MapInstanceView map_; std::unique_ptr<MapInstanceView> map_;
std::map<net::EntNum, std::unique_ptr<EntityView>> ents_; std::map<net::EntNum, std::unique_ptr<EntityView>> ents_;
float time_ = 0.0f; float time_ = 0.0f;

View File

@ -17,6 +17,8 @@ void sv::Server::Run()
{ {
using namespace std::chrono_literals; using namespace std::chrono_literals;
srand(time(NULL));
auto t_start = std::chrono::steady_clock::now(); auto t_start = std::chrono::steady_clock::now();
auto t_next = t_start; auto t_next = t_start;
auto t_prev = t_start; auto t_prev = t_start;