Move player character creation to EnterableWorld & route player events via Game

This commit is contained in:
tovjemam 2026-03-21 16:24:22 +01:00
parent d0b30ed56b
commit ba0bb5a827
14 changed files with 227 additions and 153 deletions

View File

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

View File

@ -0,0 +1,97 @@
#include "enterable_world.hpp"
#include "player_character.hpp"
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;
}
game::EnterableWorld::EnterableWorld(std::string mapname) : World(std::move(mapname)) {}
void game::EnterableWorld::InsertPlayer(Player& player, const glm::vec3& pos, float yaw)
{
CreatePlayerCharacter(player, 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;
case IN_DEBUG2:
if (enabled)
CreatePlayerCharacter(player, glm::vec3(100.0f, 100.0f, 5.0f), 0.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::CreatePlayerCharacter(Player& player, const glm::vec3& position, float yaw)
{
RemovePlayerCharacter(player);
auto& character = Spawn<PlayerCharacter>(player);
character.AddClothes("tshirt", GetRandomColor());
character.AddClothes("shorts", GetRandomColor());
// character.SetNametag("player (" + std::to_string(character.GetEntNum()) + ")");
character.SetPosition(position);
character.SetYaw(yaw);
player_characters_[&player] = &character;
return character;
}
void game::EnterableWorld::RemovePlayerCharacter(Player& player)
{
auto it = player_characters_.find(&player);
if (it != player_characters_.end())
{
it->second->Remove();
player_characters_.erase(it);
}
}

View File

@ -0,0 +1,34 @@
#pragma once
#include "world.hpp"
#include "drivable_vehicle.hpp"
namespace game
{
class Player;
class PlayerCharacter;
class EnterableWorld : public World
{
public:
EnterableWorld(std::string mapname);
// events
virtual void InsertPlayer(Player& player, 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);
private:
PlayerCharacter& CreatePlayerCharacter(Player& player, const glm::vec3& position, float yaw);
void RemovePlayerCharacter(Player& player);
private:
std::map<Player*, PlayerCharacter*> player_characters_;
};
}

View File

@ -5,43 +5,76 @@
game::Game::Game()
{
default_world_ = std::make_shared<OpenWorld>();
openworld_ = std::make_shared<OpenWorld>();
all_worlds_.push_back(openworld_.get());
}
void game::Game::Update()
{
default_world_->Update(40);
for (auto world : all_worlds_)
{
world->Update(40);
}
}
void game::Game::FinishFrame()
{
default_world_->FinishFrame();
for (auto world : all_worlds_)
{
world->FinishFrame();
}
}
void game::Game::PlayerJoined(Player& player)
{
player.SetWorld(default_world_);
players_.insert(&player);
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_);
openworld_->InsertPlayer(player, glm::vec3(100.0f, 100.0f, 5.0f), 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)
{
auto world = FindPlayerWorld(player);
if (world)
world->PlayerInput(player, type, enabled);
}
void game::Game::PlayerLeft(Player& player)
{
players_.erase(&player);
BroadcastChat(player.GetName() + "^r se vodpojil zmrd");
}
auto world = FindPlayerWorld(player);
if (world)
world->RemovePlayer(player);
bool game::Game::PlayerInput(Player& player, PlayerInputType type, bool enabled)
{
return false; // not handled here
players_.erase(&player);
BroadcastChat(player.GetName() + "^r se vodpojil zmrd");
}
void game::Game::BroadcastChat(const std::string& text)
{
for (auto player : players_)
for (auto& [player, info] : players_)
{
player->SendChat(text);
}
}
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
#include <map>
#include <set>
#include "world.hpp"
#include "enterable_world.hpp"
#include "openworld.hpp"
namespace game
{
class Player;
struct PlayerGameInfo
{
Player& player;
EnterableWorld* world = nullptr;
PlayerGameInfo(Player& player) : player(player) {}
};
class Game
{
public:
@ -19,15 +27,21 @@ public:
void FinishFrame();
void PlayerJoined(Player& player);
void PlayerViewAnglesChanged(Player& player, float yaw, float pitch);
void PlayerInput(Player& player, PlayerInputType type, bool enabled);
void PlayerLeft(Player& player);
bool PlayerInput(Player& player, PlayerInputType type, bool enabled);
private:
void BroadcastChat(const std::string& text);
EnterableWorld* FindPlayerWorld(Player& player) const;
private:
std::shared_ptr<World> default_world_;
std::set<Player*> players_;
std::shared_ptr<OpenWorld> openworld_;
std::vector<World*> all_worlds_; // for common update etc.
std::map<Player*, PlayerGameInfo> players_;
};

View File

@ -45,10 +45,8 @@ static uint32_t GetRandomColor24()
return (b << 16) | (g << 8) | r;
}
game::OpenWorld::OpenWorld() : World("openworld")
game::OpenWorld::OpenWorld() : EnterableWorld("openworld")
{
srand(time(NULL));
// spawn bots
for (size_t i = 0; i < 100; ++i)
{
@ -81,64 +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)
{
@ -151,27 +91,6 @@ static T& SpawnRandomCharacter(game::OpenWorld& world, TArgs&&... args)
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::VehicleTuning tuning;

View File

@ -1,42 +1,21 @@
#pragma once
#include "world.hpp"
#include "vehicle.hpp"
#include "character.hpp"
#include "usable.hpp"
#include "drivable_vehicle.hpp"
#include <optional>
#include "enterable_world.hpp"
#include "npc_character.hpp"
namespace game
{
class PlayerCharacter;
class NpcCharacter;
class OpenWorld : public World
class OpenWorld : public EnterableWorld
{
public:
OpenWorld();
virtual void Update(int64_t delta_time) override;
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);
private:
game::DrivableVehicle& SpawnRandomVehicle();
void SpawnBot();
private:
std::map<Player*, PlayerCharacter*> player_characters_;
std::vector<NpcCharacter*> npcs_;
};

View File

@ -6,6 +6,7 @@
#include <glm/gtx/norm.hpp>
#include "world.hpp"
#include "game.hpp"
game::Player::Player(Game& game, std::string name) : game_(game), name_(std::move(name))
{
@ -48,13 +49,7 @@ void game::Player::SetWorld(std::shared_ptr<World> world)
if (world == world_)
return;
if (world_)
world_->PlayerLeft(*this);
world_ = std::move(world);
if (world_)
world_->PlayerJoined(*this);
}
void game::Player::SetCamera(net::EntNum entnum)
@ -74,7 +69,6 @@ void game::Player::SendChat(const std::string& text)
game::Player::~Player()
{
SetWorld(nullptr);
game_.PlayerLeft(*this);
}
@ -247,9 +241,7 @@ bool game::Player::ProcessViewAnglesMsg(net::InMessage& msg)
view_yaw_ = yaw_q.Decode();
view_pitch_ = pitch_q.Decode();
if (world_)
world_->PlayerViewAnglesChanged(*this, view_yaw_, view_pitch_);
game_.PlayerViewAnglesChanged(*this, view_yaw_, view_pitch_);
return true;
}
@ -260,10 +252,6 @@ void game::Player::Input(PlayerInputType type, bool enabled)
else
in_ &= ~(1 << type);
if (!game_.PlayerInput(*this, type, enabled))
{
if (world_)
world_->PlayerInput(*this, type, enabled);
}
game_.PlayerInput(*this, type, enabled);
}

View File

@ -1,20 +1,23 @@
#pragma once
#include <set>
#include <memory>
#include <glm/glm.hpp>
#include "net/defs.hpp"
#include "net/inmessage.hpp"
#include "net/msg_producer.hpp"
#include "utils/defs.hpp"
#include "player_input.hpp"
#include "game.hpp"
namespace game
{
class Game;
class World;
class Entity;
class Vehicle;
class Player : public net::MsgProducer
{

View File

@ -1,5 +1,5 @@
#include "player_character.hpp"
#include "openworld.hpp"
#include "world.hpp"
game::PlayerCharacter::PlayerCharacter(World& world, Player& player) : Super(world), player_(player)
{

View File

@ -2,12 +2,11 @@
#include "drivable_vehicle.hpp"
#include "player.hpp"
#include "world.hpp"
namespace game
{
class OpenWorld;
class PlayerCharacter : public ControllableCharacter
{
public:

View File

@ -6,6 +6,7 @@
#include "assets/cache.hpp"
#include "utils/allocnum.hpp"
#include "collision/object_info.hpp"
#include "destroyed_object.hpp"
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)
{
auto it = ents_.find(entnum);

View File

@ -37,13 +37,7 @@ public:
virtual void Update(int64_t delta_time);
void FinishFrame();
// events
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) {}
virtual void DestructibleDestroyed(net::ObjNum num, std::unique_ptr<MapObjectCollision> col);
Entity* GetEntity(net::EntNum entnum);

View File

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