do some manual testing
some more testing
a little optimization
- and give players an appearance as well ^^
launcher ui
#include "../world/Entity.hpp"
#include "../world/World.hpp"
+#include <iostream>
+
+using namespace std;
+
namespace blank {
-Spawner::Spawner(World &world, Skeletons &skeletons, std::uint64_t seed)
+Spawner::Spawner(World &world, Skeletons &skeletons, uint64_t seed)
: world(world)
, skeletons(skeletons)
, controllers()
, despawn_range(128 * 128)
, spawn_distance(16 * 16)
, max_entities(16)
-, chunk_range(4) {
+, chunk_range(4)
+, skeletons_offset(0)
+, skeletons_length(skeletons.Size()) {
timer.Start();
}
}
+void Spawner::LimitSkeletons(size_t begin, size_t end) {
+ if (begin >= skeletons.Size() || end > skeletons.Size() || begin >= end) {
+ cout << "warning, skeleton limit out of bounds or invalid range given" << endl;
+ } else {
+ skeletons_offset = begin;
+ skeletons_length = end - begin;
+ }
+}
+
void Spawner::Update(int dt) {
CheckDespawn();
timer.Update(dt);
}
void Spawner::TrySpawn() {
- if (controllers.size() >= max_entities) return;
+ if (controllers.size() >= max_entities || skeletons_length == 0) return;
// select random player to punish
auto &players = world.Players();
e.Position(chunk, pos);
e.Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
e.WorldCollidable(true);
- skeletons[random.Next<unsigned char>() % skeletons.Size()].Instantiate(e.GetModel());
+ RandomSkeleton().Instantiate(e.GetModel());
e.AngularVelocity(rot);
Controller *ctrl;
if (random()) {
ctrl = new RandomWalk(e, random.Next<std::uint64_t>());
- e.Name("spawned walker");
+ e.Name("walker");
} else {
ctrl = new Chaser(world, e, reference);
- e.Name("spawned chaser");
+ e.Name("chaser");
}
controllers.emplace_back(ctrl);
}
+CompositeModel &Spawner::RandomSkeleton() noexcept {
+ std::size_t offset = (random.Next<std::size_t>() % skeletons_length) + skeletons_offset;
+ return skeletons[offset];
+}
+
}
namespace blank {
+class CompositeModel;
class Controller;
class Entity;
class Skeletons;
Spawner(World &, Skeletons &, std::uint64_t seed);
~Spawner();
+ void LimitSkeletons(std::size_t begin, std::size_t end);
+
void Update(int dt);
private:
void TrySpawn();
void Spawn(Entity &reference, const glm::ivec3 &, const glm::vec3 &);
+ CompositeModel &RandomSkeleton() noexcept;
+
private:
World &world;
Skeletons &skeletons;
unsigned int max_entities;
int chunk_range;
+ std::size_t skeletons_offset;
+ std::size_t skeletons_length;
+
};
}
chunk_renderer.LoadTextures(env.loader, tex_index);
chunk_renderer.FogDensity(wc.fog_density);
skeletons.Load();
+ spawner.LimitSkeletons(0, skeletons.Size());
// TODO: better solution for initializing HUD
interface.SelectNext();
}
void Skeletons::LoadHeadless() {
skeletons.clear();
- skeletons.reserve(3);
+ skeletons.reserve(4);
{
- AABB bounds{{ -0.25f, -0.5f, -0.25f }, { 0.25f, 0.5f, 0.25f }};
+ AABB bounds{{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }};
skeletons.emplace_back(new CompositeModel);
skeletons[0]->ID(1);
skeletons[0]->Bounds(bounds);
skeletons[1]->Bounds(bounds);
}
{
- AABB bounds{{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }};
+ AABB bounds{{ -0.25f, -0.5f, -0.25f }, { 0.25f, 0.5f, 0.25f }};
skeletons.emplace_back(new CompositeModel);
skeletons[2]->ID(3);
skeletons[2]->Bounds(bounds);
}
+ {
+ AABB bounds{{ -0.25f, -0.5f, -0.35f }, { 0.25f, 0.5f, 0.35f }};
+ skeletons.emplace_back(new CompositeModel);
+ skeletons[3]->ID(4);
+ skeletons[3]->Bounds(bounds);
+ }
}
void Skeletons::Load() {
LoadHeadless();
- models.resize(3);
+ models.resize(4);
EntityModel::Buffer buf;
{
CuboidShape shape(skeletons[0]->Bounds());
- shape.Vertices(buf, 1.0f);
+ shape.Vertices(buf, 3.0f);
buf.colors.resize(shape.VertexCount(), { 1.0f, 1.0f, 0.0f });
models[0].Update(buf);
skeletons[0]->SetNodeModel(&models[0]);
{
CuboidShape shape(skeletons[1]->Bounds());
buf.Clear();
- shape.Vertices(buf, 2.0f);
+ shape.Vertices(buf, 0.0f);
buf.colors.resize(shape.VertexCount(), { 0.0f, 1.0f, 1.0f });
models[1].Update(buf);
skeletons[1]->SetNodeModel(&models[1]);
{
StairShape shape(skeletons[2]->Bounds(), { 0.4f, 0.4f });
buf.Clear();
- shape.Vertices(buf, 3.0f);
+ shape.Vertices(buf, 1.0f);
buf.colors.resize(shape.VertexCount(), { 1.0f, 0.0f, 1.0f });
models[2].Update(buf);
skeletons[2]->SetNodeModel(&models[2]);
}
+ {
+ CuboidShape shape(skeletons[3]->Bounds());
+ buf.Clear();
+ shape.Vertices(buf, 2.0f);
+ buf.colors.resize(shape.VertexCount(), { 1.0f, 0.25f, 0.5f });
+ models[3].Update(buf);
+ skeletons[3]->SetNodeModel(&models[3]);
+ }
}
CompositeModel *Skeletons::ByID(std::uint16_t id) noexcept {
namespace blank {
+
+class CompositeModel;
+
namespace server {
class Server;
ChunkIndex &PlayerChunks() noexcept { return *player.chunks; }
const ChunkIndex &PlayerChunks() const noexcept { return *player.chunks; }
+ void SetPlayerModel(const CompositeModel &) noexcept;
+ bool HasPlayerModel() const noexcept;
+ const CompositeModel &GetPlayerModel() const noexcept;
+
private:
struct SpawnStatus {
// the entity in question
Server &server;
Connection conn;
Player player;
+ const CompositeModel *player_model;
std::list<SpawnStatus> spawns;
unsigned int confirm_wait;
namespace blank {
+class CompositeModel;
class World;
namespace server {
World &GetWorld() noexcept { return world; }
+ void SetPlayerModel(const CompositeModel &) noexcept;
+ bool HasPlayerModel() const noexcept;
+ const CompositeModel &GetPlayerModel() const noexcept;
+
private:
void HandlePacket(const UDPpacket &);
std::list<ClientConnection> clients;
World &world;
+ const CompositeModel *player_model;
};
TextureIndex tex_index;
env.loader.LoadBlockTypes("default", block_types, tex_index);
skeletons.LoadHeadless();
+ spawner.LimitSkeletons(1, skeletons.Size());
+ server.SetPlayerModel(skeletons[0]);
loop_timer.Start();
#include "Server.hpp"
#include "../app/init.hpp"
+#include "../model/CompositeModel.hpp"
#include "../world/ChunkIndex.hpp"
#include "../world/Entity.hpp"
#include "../world/World.hpp"
: server(server)
, conn(addr)
, player(nullptr, nullptr)
+, player_model(nullptr)
, spawns()
, confirm_wait(0)
, entity_updates()
}
}
}
+ if (HasPlayerModel()) {
+ GetPlayerModel().Instantiate(player.entity->GetModel());
+ }
cout << "player \"" << player.entity->Name() << "\" joined" << endl;
}
chunk_queue.clear();
}
+void ClientConnection::SetPlayerModel(const CompositeModel &m) noexcept {
+ player_model = &m;
+ if (HasPlayer()) {
+ m.Instantiate(PlayerEntity().GetModel());
+ }
+}
+
+bool ClientConnection::HasPlayerModel() const noexcept {
+ return player_model;
+}
+
+const CompositeModel &ClientConnection::GetPlayerModel() const noexcept {
+ return *player_model;
+}
+
void ClientConnection::OnPacketReceived(uint16_t seq) {
if (transmitter.Waiting()) {
transmitter.Ack(seq);
: serv_sock(nullptr)
, serv_pack{ -1, nullptr, 0 }
, clients()
-, world(world) {
+, world(world)
+, player_model(nullptr) {
serv_sock = SDLNet_UDP_Open(conf.port);
if (!serv_sock) {
throw NetError("SDLNet_UDP_Open");
}
}
clients.emplace_back(*this, addr);
+ if (HasPlayerModel()) {
+ clients.back().SetPlayerModel(GetPlayerModel());
+ }
return clients.back();
}
void Server::Update(int dt) {
for (list<ClientConnection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
- client->Update(dt);
if (client->Disconnected()) {
client = clients.erase(client);
} else {
}
}
+void Server::SetPlayerModel(const CompositeModel &m) noexcept {
+ player_model = &m;
+ for (ClientConnection &client : clients) {
+ client.SetPlayerModel(m);
+ }
+}
+
+bool Server::HasPlayerModel() const noexcept {
+ return player_model;
+}
+
+const CompositeModel &Server::GetPlayerModel() const noexcept {
+ return *player_model;
+}
+
}
}