From dbfcb12348b80e2582f710acb1e4ed0011889ba2 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Wed, 2 Sep 2015 21:18:49 +0200 Subject: [PATCH] special treatment for players with some drawbacks and cut corners, but more to come --- running | 9 +-- src/ai/Spawner.cpp | 31 +++++++--- src/ai/Spawner.hpp | 3 +- src/app/WorldState.cpp | 10 ++-- src/app/runtime.cpp | 8 +++ src/ui/Interface.hpp | 11 ++-- src/ui/Keymap.hpp | 5 -- src/ui/ui.cpp | 125 +---------------------------------------- src/world/World.cpp | 37 +++++++----- src/world/World.hpp | 11 +++- 10 files changed, 80 insertions(+), 170 deletions(-) diff --git a/running b/running index 7c089ff..846f27d 100644 --- a/running +++ b/running @@ -69,6 +69,11 @@ Network --port port number to connection to (client) or listen on (server) +--player-name + use given name to identify with the server (client mode) + default player name is "default" + the server will reject players with names that are already taken + World ----- @@ -97,10 +102,6 @@ flip through available blocks. Q changes the face of the active block (loops over up, down, right, left, front, and back) and E changes the turn (none, left, around, and right). -Pressing B prints details about the block you're pointing at and P prints -info about the active block. L spits out the player position and light -level there. C dumps info about the chunk of the pointed at block. - Press N to toggle player/world collision. F1 toggles UI rendering. diff --git a/src/ai/Spawner.cpp b/src/ai/Spawner.cpp index fb2a1ea..6a692b1 100644 --- a/src/ai/Spawner.cpp +++ b/src/ai/Spawner.cpp @@ -52,7 +52,6 @@ Spawner::Spawner(World &world, std::uint64_t seed) } timer.Start(); - Spawn(world.Player().ChunkCoords(), { 0.5f, 0.5f, 0.5f }); } Spawner::~Spawner() { @@ -75,7 +74,7 @@ void Spawner::Update(int dt) { void Spawner::CheckDespawn() noexcept { - const Entity &reference = world.Player(); + const auto &refs = world.Players(); for (auto iter = controllers.begin(), end = controllers.end(); iter != end;) { Entity &e = (*iter)->Controlled(); if (e.Dead()) { @@ -83,8 +82,15 @@ void Spawner::CheckDespawn() noexcept { iter = controllers.erase(iter); continue; } - glm::vec3 diff(reference.AbsoluteDifference(e)); - if (dot(diff, diff) > despawn_range) { + bool safe = false; + for (const Entity *ref : refs) { + glm::vec3 diff(ref->AbsoluteDifference(e)); + if (dot(diff, diff) < despawn_range) { + safe = true; + break; + } + } + if (!safe) { e.Kill(); delete *iter; iter = controllers.erase(iter); @@ -97,6 +103,11 @@ void Spawner::CheckDespawn() noexcept { void Spawner::TrySpawn() { if (controllers.size() >= max_entities) return; + // select random player to punish + auto &players = world.Players(); + if (players.size() == 0) return; + Entity &player = *players[random.Next() % players.size()]; + glm::ivec3 chunk( (random.Next() % (chunk_range * 2 + 1)) - chunk_range, (random.Next() % (chunk_range * 2 + 1)) - chunk_range, @@ -111,14 +122,16 @@ void Spawner::TrySpawn() { // distance check - glm::vec3 diff(glm::vec3(chunk * Chunk::Extent() - pos) + world.Player().Position()); + glm::vec3 diff(glm::vec3(chunk * Chunk::Extent() - pos) + player.Position()); float dist = dot(diff, diff); if (dist > despawn_range || dist < spawn_distance) { return; } // check if the spawn block and the one above it are loaded and inhabitable - BlockLookup spawn_block(&world.PlayerChunk(), chunk * Chunk::Extent() + pos); + BlockLookup spawn_block( + world.Loader().Loaded(player.ChunkCoords()), + chunk * Chunk::Extent() + pos); if (!spawn_block || spawn_block.GetType().collide_block) { return; } @@ -128,10 +141,10 @@ void Spawner::TrySpawn() { return; } - Spawn(world.Player().ChunkCoords() + chunk, glm::vec3(pos) + glm::vec3(0.5f)); + Spawn(player, player.ChunkCoords() + chunk, glm::vec3(pos) + glm::vec3(0.5f)); } -void Spawner::Spawn(const glm::ivec3 &chunk, const glm::vec3 &pos) { +void Spawner::Spawn(Entity &reference, const glm::ivec3 &chunk, const glm::vec3 &pos) { glm::vec3 rot(0.000001f); rot.x *= (random.Next() % 1024); rot.y *= (random.Next() % 1024); @@ -148,7 +161,7 @@ void Spawner::Spawn(const glm::ivec3 &chunk, const glm::vec3 &pos) { if (random()) { ctrl = new RandomWalk(e, random.Next()); } else { - ctrl = new Chaser(world, e, world.Player()); + ctrl = new Chaser(world, e, reference); } controllers.emplace_back(ctrl); } diff --git a/src/ai/Spawner.hpp b/src/ai/Spawner.hpp index 9fb3d36..a1181d3 100644 --- a/src/ai/Spawner.hpp +++ b/src/ai/Spawner.hpp @@ -13,6 +13,7 @@ namespace blank { class Controller; +class Entity; class World; class Spawner { @@ -26,7 +27,7 @@ public: private: void CheckDespawn() noexcept; void TrySpawn(); - void Spawn(const glm::ivec3 &, const glm::vec3 &); + void Spawn(Entity &reference, const glm::ivec3 &, const glm::vec3 &); private: World &world; diff --git a/src/app/WorldState.cpp b/src/app/WorldState.cpp index 03abe36..521f5b5 100644 --- a/src/app/WorldState.cpp +++ b/src/app/WorldState.cpp @@ -70,20 +70,20 @@ void WorldState::Update(int dt) { interface.Update(dt); spawner.Update(dt); world.Update(dt); - chunk_renderer.Rebase(world.Player().ChunkCoords()); + chunk_renderer.Rebase(interface.Player().ChunkCoords()); chunk_renderer.Update(dt); - glm::mat4 trans = world.Player().Transform(world.Player().ChunkCoords()); + glm::mat4 trans = interface.Player().Transform(interface.Player().ChunkCoords()); glm::vec3 dir(trans * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f)); glm::vec3 up(trans * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f)); - env.audio.Position(world.Player().Position()); - env.audio.Velocity(world.Player().Velocity()); + env.audio.Position(interface.Player().Position()); + env.audio.Velocity(interface.Player().Velocity()); env.audio.Orientation(dir, up); } void WorldState::Render(Viewport &viewport) { - viewport.WorldPosition(world.Player().Transform(world.Player().ChunkCoords())); + viewport.WorldPosition(interface.Player().Transform(interface.Player().ChunkCoords())); chunk_renderer.Render(viewport); world.Render(viewport); interface.Render(viewport); diff --git a/src/app/runtime.cpp b/src/app/runtime.cpp index 2f0f82e..f979c65 100644 --- a/src/app/runtime.cpp +++ b/src/app/runtime.cpp @@ -142,6 +142,14 @@ void Runtime::ReadArgs(int argc, const char *const *argv) { config.server.port = strtoul(argv[i], nullptr, 10); config.client.port = config.server.port; } + } else if (strcmp(param, "player-name") == 0) { + ++i; + if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') { + cerr << "missing argument to --player-name" << endl; + error = true; + } else { + config.interface.player_name = argv[i]; + } } else if (strcmp(param, "save-path") == 0) { ++i; if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') { diff --git a/src/ui/Interface.hpp b/src/ui/Interface.hpp index 5cf8207..aab8b15 100644 --- a/src/ui/Interface.hpp +++ b/src/ui/Interface.hpp @@ -28,6 +28,8 @@ class Interface { public: struct Config { + std::string player_name = "default"; + float move_velocity = 0.005f; float pitch_sensitivity = -0.0025f; float yaw_sensitivity = -0.001f; @@ -40,6 +42,9 @@ public: Interface(const Config &, Environment &, World &); + Entity &Player() noexcept { return ctrl.Controlled(); } + const Entity &Player() const noexcept { return ctrl.Controlled(); } + void HandlePress(const SDL_KeyboardEvent &); void HandleRelease(const SDL_KeyboardEvent &); void Handle(const SDL_MouseMotionEvent &); @@ -56,12 +61,6 @@ public: void PlaceBlock(); void RemoveBlock() noexcept; - void PrintBlockInfo(); - void PrintChunkInfo(); - void PrintLightInfo(); - void PrintSelectionInfo(); - void Print(const Block &); - void SelectNext(); void SelectPrevious(); diff --git a/src/ui/Keymap.hpp b/src/ui/Keymap.hpp index e96179a..0e34ba9 100644 --- a/src/ui/Keymap.hpp +++ b/src/ui/Keymap.hpp @@ -35,11 +35,6 @@ public: TOGGLE_VISUAL, TOGGLE_DEBUG, - PRINT_BLOCK, - PRINT_CHUNK, - PRINT_LIGHT, - PRINT_SELECTION, - EXIT, }; diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index e637661..d8459e5 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -105,7 +105,8 @@ Interface::Interface( World &world) : env(env) , world(world) -, ctrl(world.Player()) +// let's assume this succeeds and hope for the best for now +, ctrl(*world.AddPlayer(config.player_name)) , hud(world.BlockTypes(), env.assets.small_ui_font) , aim{{ 0, 0, 0 }, { 0, 0, -1 }} , aim_world() @@ -204,19 +205,6 @@ void Interface::HandlePress(const SDL_KeyboardEvent &event) { ToggleCollision(); break; - case Keymap::PRINT_BLOCK: - PrintBlockInfo(); - break; - case Keymap::PRINT_CHUNK: - PrintChunkInfo(); - break; - case Keymap::PRINT_LIGHT: - PrintLightInfo(); - break; - case Keymap::PRINT_SELECTION: - PrintSelectionInfo(); - break; - case Keymap::TOGGLE_VISUAL: ToggleVisual(); break; @@ -283,92 +271,6 @@ void Interface::ToggleCollision() { } } -void Interface::PrintBlockInfo() { - std::cout << std::endl; - if (!aim_world) { - PostMessage("not looking at any block"); - Ray aim = ctrl.Aim(); - std::stringstream s; - s << "aim ray: " << aim.orig << ", " << aim.dir; - PostMessage(s.str()); - return; - } - std::stringstream s; - s << "looking at block " << aim_world.block - << " " << aim_world.BlockCoords() - << " of chunk " << aim_world.GetChunk().Position() - ; - PostMessage(s.str()); - Print(aim_world.GetBlock()); -} - -void Interface::PrintChunkInfo() { - std::cout << std::endl; - if (!aim_world) { - PostMessage("not looking at any block"); - return; - } - std::stringstream s; - s << "looking at chunk " << aim_world.GetChunk().Position(); - PostMessage(s.str()); - - PostMessage(" neighbors:"); - if (aim_world.GetChunk().HasNeighbor(Block::FACE_LEFT)) { - s.str(""); - s << " left " << aim_world.GetChunk().GetNeighbor(Block::FACE_LEFT).Position(); - PostMessage(s.str()); - } - if (aim_world.GetChunk().HasNeighbor(Block::FACE_RIGHT)) { - s.str(""); - s << " right " << aim_world.GetChunk().GetNeighbor(Block::FACE_RIGHT).Position(); - PostMessage(s.str()); - } - if (aim_world.GetChunk().HasNeighbor(Block::FACE_UP)) { - s.str(""); - s << " up " << aim_world.GetChunk().GetNeighbor(Block::FACE_UP).Position(); - PostMessage(s.str()); - } - if (aim_world.GetChunk().HasNeighbor(Block::FACE_DOWN)) { - s.str(""); - s << " down " << aim_world.GetChunk().GetNeighbor(Block::FACE_DOWN).Position(); - PostMessage(s.str()); - } - if (aim_world.GetChunk().HasNeighbor(Block::FACE_FRONT)) { - s.str(""); - s << " front " << aim_world.GetChunk().GetNeighbor(Block::FACE_FRONT).Position(); - PostMessage(s.str()); - } - if (aim_world.GetChunk().HasNeighbor(Block::FACE_BACK)) { - s.str(""); - s << " back " << aim_world.GetChunk().GetNeighbor(Block::FACE_BACK).Position(); - PostMessage(s.str()); - } - std::cout << std::endl; -} - -void Interface::PrintLightInfo() { - std::stringstream s; - s - << "light level " << world.PlayerChunk().GetLight(world.Player().Position()) - << " at position " << world.Player().Position() - ; - PostMessage(s.str()); -} - -void Interface::PrintSelectionInfo() { - std::cout << std::endl; - Print(selection); -} - -void Interface::Print(const Block &block) { - std::stringstream s; - s << "type: " << block.type - << ", face: " << block.GetFace() - << ", turn: " << block.GetTurn() - ; - PostMessage(s.str()); -} - void Interface::ToggleAudio() { config.audio_disabled = !config.audio_disabled; if (config.audio_disabled) { @@ -623,7 +525,7 @@ void Interface::UpdateOutline() { outl_buf.Clear(); aim_world.GetType().FillOutlineModel(outl_buf); outline.Update(outl_buf); - outline_transform = aim_world.GetChunk().Transform(world.Player().ChunkCoords()); + outline_transform = aim_world.GetChunk().Transform(Player().ChunkCoords()); outline_transform *= aim_world.BlockTransform(); outline_transform *= glm::scale(glm::vec3(1.005f)); } @@ -710,11 +612,6 @@ void Keymap::LoadDefault() { Map(SDL_SCANCODE_F3, TOGGLE_DEBUG); Map(SDL_SCANCODE_F4, TOGGLE_AUDIO); - Map(SDL_SCANCODE_B, PRINT_BLOCK); - Map(SDL_SCANCODE_C, PRINT_CHUNK); - Map(SDL_SCANCODE_L, PRINT_LIGHT); - Map(SDL_SCANCODE_P, PRINT_SELECTION); - Map(SDL_SCANCODE_ESCAPE, EXIT); } @@ -806,14 +703,6 @@ const char *Keymap::ActionToString(Action action) { return "toggle_visual"; case TOGGLE_DEBUG: return "toggle_debug"; - case PRINT_BLOCK: - return "print_block"; - case PRINT_CHUNK: - return "print_chunk"; - case PRINT_LIGHT: - return "print_light"; - case PRINT_SELECTION: - return "print_selection"; case EXIT: return "exit"; } @@ -854,14 +743,6 @@ Keymap::Action Keymap::StringToAction(const std::string &str) { return TOGGLE_VISUAL; } else if (str == "toggle_debug") { return TOGGLE_DEBUG; - } else if (str == "print_block") { - return PRINT_BLOCK; - } else if (str == "print_chunk") { - return PRINT_CHUNK; - } else if (str == "print_light") { - return PRINT_LIGHT; - } else if (str == "print_selection") { - return PRINT_SELECTION; } else if (str == "exit") { return EXIT; } else { diff --git a/src/world/World.cpp b/src/world/World.cpp index 1d25e01..06ccb62 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -15,24 +15,35 @@ namespace blank { World::World(const BlockTypeRegistry &types, const Config &config, const WorldSave &save) -: block_type(types) +: config(config) +, block_type(types) , generate(config.gen) , chunks(config.load, types, generate, save) -, player() +, players() , entities() , light_direction(config.light_direction) , fog_density(config.fog_density) { generate.Space(0); generate.Light(13); generate.Solids({ 1, 4, 7, 10 }); +} - player = &AddEntity(); - player->Name("player"); - player->Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } }); - player->WorldCollidable(true); - player->Position(config.spawn); - chunks.QueueSurrounding(player->ChunkCoords()); +Entity *World::AddPlayer(const std::string &name) { + for (Entity *e : players) { + if (e->Name() == name) { + return nullptr; + } + } + Entity &player = AddEntity(); + player.Name(name); + // TODO: load from save file here + player.Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } }); + player.WorldCollidable(true); + player.Position(config.spawn); + players.push_back(&player); + chunks.QueueSurrounding(player.ChunkCoords()); + return &player; } @@ -133,11 +144,6 @@ bool World::Intersection(const Entity &e, std::vector &col) { } -Chunk &World::PlayerChunk() { - return chunks.ForceLoad(player->ChunkCoords()); -} - - namespace { std::vector col; @@ -162,7 +168,8 @@ void World::Update(int dt) { ++iter; } } - chunks.Rebase(player->ChunkCoords()); + // TODO: make flexible + chunks.Rebase(players[0]->ChunkCoords()); chunks.Update(dt); } @@ -205,7 +212,7 @@ void World::Render(Viewport &viewport) { entity_prog.SetFogDensity(fog_density); for (Entity &entity : entities) { - entity.Render(entity.ChunkTransform(player->ChunkCoords()), entity_prog); + entity.Render(entity.ChunkTransform(players[0]->ChunkCoords()), entity_prog); } } diff --git a/src/world/World.hpp b/src/world/World.hpp index 76cdeb2..3981b28 100644 --- a/src/world/World.hpp +++ b/src/world/World.hpp @@ -63,22 +63,27 @@ public: const BlockTypeRegistry &BlockTypes() noexcept { return block_type; } ChunkLoader &Loader() noexcept { return chunks; } - Entity &Player() { return *player; } + /// add player with given name + /// returns nullptr if the name is already taken + Entity *AddPlayer(const std::string &name); Entity &AddEntity() { entities.emplace_back(); return entities.back(); } - Chunk &PlayerChunk(); + const std::vector &Players() const noexcept { return players; } + const std::list &Entities() const noexcept { return entities; } void Update(int dt); void Render(Viewport &); private: + Config config; + const BlockTypeRegistry &block_type; Generator generate; ChunkLoader chunks; - Entity *player; + std::vector players; std::list entities; glm::vec3 light_direction; -- 2.39.2