1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

Allow managing object observers

-----

Co-authored-by: sfan5 <sfan5@live.de>
Co-authored-by: SmallJoker <SmallJoker@users.noreply.github.com>
This commit is contained in:
Lars Mueller 2023-11-12 15:28:29 +01:00 committed by sfan5
parent cc8e7a569e
commit 6874c358ea
15 changed files with 284 additions and 22 deletions

View file

@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_converter.h"
#include "common/c_content.h"
#include "log.h"
#include "player.h"
#include "server/serveractiveobject.h"
#include "tool.h"
#include "remoteplayer.h"
#include "server.h"
@ -36,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server/player_sao.h"
#include "server/serverinventorymgr.h"
#include "server/unit_sao.h"
#include "util/string.h"
using object_t = ServerActiveObject::object_t;
@ -837,6 +840,85 @@ int ObjectRef::l_get_properties(lua_State *L)
return 1;
}
// set_observers(self, observers)
int ObjectRef::l_set_observers(lua_State *L)
{
GET_ENV_PTR;
ObjectRef *ref = checkObject<ObjectRef>(L, 1);
ServerActiveObject *sao = getobject(ref);
if (sao == nullptr)
throw LuaError("Invalid ObjectRef");
// Reset object to "unmanaged" (sent to everyone)?
if (lua_isnoneornil(L, 2)) {
sao->m_observers.reset();
return 0;
}
std::unordered_set<std::string> observer_names;
lua_pushnil(L);
while (lua_next(L, 2) != 0) {
std::string name = readParam<std::string>(L, -2);
if (name.empty())
throw LuaError("Observer name is empty");
if (name.size() > PLAYERNAME_SIZE)
throw LuaError("Observer name is too long");
if (!string_allowed(name, PLAYERNAME_ALLOWED_CHARS))
throw LuaError("Observer name contains invalid characters");
if (!lua_toboolean(L, -1)) // falsy value?
throw LuaError("Values in the `observers` table need to be true");
observer_names.insert(std::move(name));
lua_pop(L, 1); // pop value, keep key
}
RemotePlayer *player = getplayer(ref);
if (player != nullptr) {
observer_names.insert(player->getName());
}
sao->m_observers = std::move(observer_names);
return 0;
}
template<typename F>
static int get_observers(lua_State *L, F observer_getter)
{
ObjectRef *ref = ObjectRef::checkObject<ObjectRef>(L, 1);
ServerActiveObject *sao = ObjectRef::getobject(ref);
if (sao == nullptr)
throw LuaError("invalid ObjectRef");
const auto observers = observer_getter(sao);
if (!observers) {
lua_pushnil(L);
return 1;
}
// Push set of observers {[name] = true}
lua_createtable(L, 0, observers->size());
for (auto &name : *observers) {
lua_pushboolean(L, true);
lua_setfield(L, -2, name.c_str());
}
return 1;
}
// get_observers(self)
int ObjectRef::l_get_observers(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
return get_observers(L, [](auto sao) { return sao->m_observers; });
}
// get_effective_observers(self)
int ObjectRef::l_get_effective_observers(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
return get_observers(L, [](auto sao) {
// The cache may be outdated, so we always have to recalculate.
return sao->recalculateEffectiveObservers();
});
}
// is_player(self)
int ObjectRef::l_is_player(lua_State *L)
{
@ -2676,6 +2758,9 @@ luaL_Reg ObjectRef::methods[] = {
luamethod(ObjectRef, get_properties),
luamethod(ObjectRef, set_nametag_attributes),
luamethod(ObjectRef, get_nametag_attributes),
luamethod(ObjectRef, set_observers),
luamethod(ObjectRef, get_observers),
luamethod(ObjectRef, get_effective_observers),
luamethod_aliased(ObjectRef, set_velocity, setvelocity),
luamethod_aliased(ObjectRef, add_velocity, add_player_velocity),