diff --git a/src/logic/scripting/lua/libs/libplayer.cpp b/src/logic/scripting/lua/libs/libplayer.cpp index 320db362..45c396fe 100644 --- a/src/logic/scripting/lua/libs/libplayer.cpp +++ b/src/logic/scripting/lua/libs/libplayer.cpp @@ -322,6 +322,38 @@ static int l_set_suspended(lua::State* L) { return 0; } +static int l_get_all_in_radius(lua::State* L) { + auto center = lua::tovec3(L, 1); + auto radius = static_cast(lua::tonumber(L, 2)); + + auto players = level->players->getAllInRadius(center, radius); + lua::createtable(L, players.size(), 0); + for (size_t i = 0; i < players.size(); i++) { + lua::pushinteger(L, players[i]->getId()); + lua::rawseti(L, i + 1); + } + return 1; +} + +static int l_get_all(lua::State* L) { + auto players = level->players->getAll(); + lua::createtable(L, players.size(), 0); + for (size_t i = 0; i < players.size(); i++) { + lua::pushinteger(L, players[i]->getId()); + lua::rawseti(L, i + 1); + } + return 1; +} + +static int l_get_nearest(lua::State* L) { + auto position = lua::tovec3(L, 1); + if (auto player = level->players->getNearest(position)) { + lua::pushinteger(L, player->getId()); + return 1; + } + return 0; +} + const luaL_Reg playerlib[] = { {"get_pos", lua::wrap}, {"set_pos", lua::wrap}, @@ -358,5 +390,8 @@ const luaL_Reg playerlib[] = { {"set_name", lua::wrap}, {"create", lua::wrap}, {"delete", lua::wrap}, + {"get_all_in_radius", lua::wrap}, + {"get_all", lua::wrap}, + {"get_nearest", lua::wrap}, {nullptr, nullptr} }; diff --git a/src/objects/Players.cpp b/src/objects/Players.cpp index 9c0e2603..5fc59f40 100644 --- a/src/objects/Players.cpp +++ b/src/objects/Players.cpp @@ -1,5 +1,8 @@ #include "Players.hpp" +#define GLM_ENABLE_EXPERIMENTAL +#include + #include "Player.hpp" #include "items/Inventories.hpp" #include "world/Level.hpp" @@ -20,6 +23,48 @@ Player* Players::get(int64_t id) const { return found->second.get(); } +std::vector Players::getAllInRadius( + const glm::vec3& center, float radius +) const { + std::vector foundPlayers; + + for (const auto& pair : players) { + auto player = pair.second.get(); + auto relativePos = player->getPosition() - center; + if (!player->isSuspended() && glm::length2(relativePos) <= radius) { + foundPlayers.emplace_back(player); + } + } + return foundPlayers; +} + +std::vector Players::getAll() const { + std::vector allPlayers; + allPlayers.reserve(players.size()); + for (const auto& pair : players) { + allPlayers.emplace_back(pair.second.get()); + } + return allPlayers; +} + +Player* Players::getNearest(const glm::vec3& position) const { + Player* nearest = nullptr; + float nearestDist2 = std::numeric_limits::max(); + for (const auto& pair : players) { + auto player = pair.second.get(); + if (player->isSuspended()) { + continue; + } + auto relativePos = player->getPosition() - position; + auto dist2 = glm::length2(relativePos); + if (dist2 < nearestDist2) { + nearestDist2 = dist2; + nearest = player; + } + } + return nearest; +} + Player* Players::create(int64_t id) { int64_t& nextPlayerID = level.getWorld()->getInfo().nextPlayerId; if (id == NONE) { diff --git a/src/objects/Players.hpp b/src/objects/Players.hpp index 5c657a50..16803340 100644 --- a/src/objects/Players.hpp +++ b/src/objects/Players.hpp @@ -1,7 +1,9 @@ #pragma once #include +#include #include +#include #include "typedefs.hpp" #include "interfaces/Serializable.hpp" @@ -34,6 +36,10 @@ public: void remove(int64_t id); + std::vector getAllInRadius(const glm::vec3& center, float radius) const; + std::vector getAll() const; + Player* getNearest(const glm::vec3& position) const; + dv::value serialize() const override; void deserialize(const dv::value& src) override;