This commit is contained in:
sfence 2024-04-04 00:42:50 +07:00 committed by GitHub
commit 323a39511f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 349 additions and 30 deletions

View File

@ -39,6 +39,7 @@ core.features = {
dynamic_add_media_filepath = true, dynamic_add_media_filepath = true,
lsystem_decoration_type = true, lsystem_decoration_type = true,
item_meta_range = true, item_meta_range = true,
have_guids = true,
} }
function core.has_feature(arg) function core.has_feature(arg)

View File

@ -5432,6 +5432,8 @@ Utilities
lsystem_decoration_type = true, lsystem_decoration_type = true,
-- Overrideable pointing range using the itemstack meta key `"range"` (5.9.0) -- Overrideable pointing range using the itemstack meta key `"range"` (5.9.0)
item_meta_range = true, item_meta_range = true,
-- objects have get_guid method and lua entities alse set_guid method (5.9.0)
have_guids = true,
} }
``` ```
@ -7283,6 +7285,8 @@ Global tables
as they are only read when spawning. as they are only read when spawning.
* `minetest.object_refs` * `minetest.object_refs`
* Map of object references, indexed by active object id * Map of object references, indexed by active object id
* `minetest.objects_by_guid`
* Map of object references, indexed by active object GUID
* `minetest.luaentities` * `minetest.luaentities`
* Map of Lua entities, indexed by active object id * Map of Lua entities, indexed by active object id
* `minetest.registered_abms` * `minetest.registered_abms`
@ -7934,6 +7938,9 @@ child will follow movement and rotation of that bone.
-- Default: false -- Default: false
} }
``` ```
* `get_guid()`: returns a global unique identifier (a string)
* For players a global unique identiticator is a player name.
* For non-player objects, it is unique generated string.
#### Lua entity only (no-op for other objects) #### Lua entity only (no-op for other objects)
@ -7941,6 +7948,10 @@ child will follow movement and rotation of that bone.
* The object is removed after returning from Lua. However the `ObjectRef` * The object is removed after returning from Lua. However the `ObjectRef`
itself instantly becomes unusable with all further method calls having itself instantly becomes unusable with all further method calls having
no effect and returning `nil`. no effect and returning `nil`.
* `set_guid(guid)`:
* Set a global unique identifier string of entity.
* Is valid to be called only in `on_activate` callback.
* Should be used ONLY for restoring saved guid from staticdata!!!
* `set_velocity(vel)` * `set_velocity(vel)`
* Sets the velocity * Sets the velocity
* `vel` is a vector, e.g. `{x=0.0, y=2.3, z=1.0}` * `vel` is a vector, e.g. `{x=0.0, y=2.3, z=1.0}`

View File

@ -582,6 +582,9 @@ Since protocol version 37:
* `u8` `version2` (=1) * `u8` `version2` (=1)
* `s32` pitch * 1000 * `s32` pitch * 1000
* `s32` roll * 1000 * `s32` roll * 1000
* if version2 >= 2:
* u32 len
* u8[len] guid
# Itemstring Format # Itemstring Format

View File

@ -52,6 +52,22 @@ core.register_entity("unittests:callbacks", {
end, end,
}) })
core.register_entity("unittests:guid", {
initial_properties = {
static_save = false,
},
on_activate = function(self, staticdata, dtime_s)
self.object:set_guid("@UNITTEST")
insert_log("on_activate(%d)", #staticdata)
end,
on_deactivate = function(self, removal)
insert_log("on_deactivate(%s)", tostring(removal))
end,
get_staticdata = function(self)
assert(false)
end,
})
-- --
local function check_log(expect) local function check_log(expect)
@ -130,3 +146,26 @@ local function test_entity_attach(player, pos)
obj:remove() obj:remove()
end end
unittests.register("test_entity_attach", test_entity_attach, {player=true, map=true}) unittests.register("test_entity_attach", test_entity_attach, {player=true, map=true})
local function test_entity_guid(_, pos)
log = {}
local obj = core.add_entity(pos, "unittests:callbacks")
check_log({"on_activate(0)"})
assert(obj:get_guid()~="")
obj:remove()
check_log({"on_deactivate(true)"})
assert(core.objects_by_guid["@UNITTEST"]==nil)
obj = core.add_entity(pos, "unittests:guid")
check_log({"on_activate(0)"})
assert(obj:get_guid()=="@UNITTEST")
assert(core.objects_by_guid["@UNITTEST"]~=nil)
obj:remove()
end
unittests.register("test_entity_guid", test_entity_guid, {map=true})

View File

@ -84,3 +84,10 @@ local function run_player_add_pos_tests(player)
end end
unittests.register("test_player_add_pos", run_player_add_pos_tests, {player=true}) unittests.register("test_player_add_pos", run_player_add_pos_tests, {player=true})
--
-- Player get uuid
--
local function test_player_guid_tests(player)
assert(player:get_guid()==player:get_player_name())
end
unittests.register("test_player_guid", test_player_guid_tests, {player=true})

View File

@ -381,6 +381,7 @@ set(common_SRCS
face_position_cache.cpp face_position_cache.cpp
filesys.cpp filesys.cpp
gettext.cpp gettext.cpp
guid.cpp
httpfetch.cpp httpfetch.cpp
hud.cpp hud.cpp
inventory.cpp inventory.cpp

50
src/guid.cpp Normal file
View File

@ -0,0 +1,50 @@
/*
Minetest
Copyright (C) 2021, DS
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "guid.h"
#include <sstream>
#include "serverenvironment.h"
#include "util/base64.h"
GUIdGenerator::GUIdGenerator() :
m_uniform(0, UINT64_MAX)
{
m_rand_usable = m_rand.entropy() > 0.01;
}
GUId GUIdGenerator::next(const std::string &prefix)
{
std::stringstream s_guid;
u64 a[2];
if (m_rand_usable) {
a[0] = m_uniform(m_rand);
a[1] = m_uniform(m_rand);
}
else {
a[0] = (static_cast<u64>(m_env->getGameTime()) << 32) + m_next;
a[1] = m_uniform(m_rand);
m_next++;
}
s_guid << prefix << base64_encode(std::string_view(reinterpret_cast<char *>(a), 16));
return s_guid.str();
}

68
src/guid.h Normal file
View File

@ -0,0 +1,68 @@
/*
Minetest
Copyright (C) 2021, DS
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "irrlichttypes.h"
#include "util/basic_macros.h"
#include <random>
#include <string>
class ServerEnvironment;
/**
* A global unique identifier.
* It is global because it stays valid in a world forever.
* It is unique because there are no collisions.
*/
typedef std::string GUId;
/**
* Generates infinitely many guids.
*/
class GUIdGenerator {
public:
/**
* Creates a new uninitialized generator.
* @param env ServerEnvironment where generator is running
* @param prefix Prefix of generated GUId
* @param next next value getted from loadMeta
*/
GUIdGenerator();
~GUIdGenerator() = default;
DISABLE_CLASS_COPY(GUIdGenerator)
/**
* Generates the next guid, which it will never return again.
* @return the new guid, or "" if the generator is not yet initialized
*/
GUId next(const std::string &prefix);
private:
void setServerEnvironment(ServerEnvironment *env) { m_env = env; }
ServerEnvironment *m_env;
std::random_device m_rand;
std::uniform_int_distribution<u64> m_uniform;
bool m_rand_usable;
u32 m_next;
friend class ServerEnvironment;
};

View File

@ -433,11 +433,12 @@ void ScriptApiBase::setOriginFromTableRaw(int index, const char *fxn)
/* /*
* How ObjectRefs are handled in Lua: * How ObjectRefs are handled in Lua:
* When an active object is created, an ObjectRef is created on the Lua side * When an active object is created, an ObjectRef is created on the Lua side
* and stored in core.object_refs[id]. * and stored in core.object_refs[id] and in core.objects_by_guids[[GUID].
* Methods that require an ObjectRef to a certain object retrieve it from that * Methods that require an ObjectRef to a certain object retrieve it from that
* table instead of creating their own.(*) * table instead of creating their own.(*)
* When an active object is removed, the existing ObjectRef is invalidated * When an active object is removed, the existing ObjectRef is invalidated
* using ::set_null() and removed from the core.object_refs table. * using ::set_null() and removed from the core.object_refs and
* core.object_by_guids tables.
* (*) An exception to this are NULL ObjectRefs and anonymous ObjectRefs * (*) An exception to this are NULL ObjectRefs and anonymous ObjectRefs
* for objects without ID. * for objects without ID.
* It's unclear what the latter are needed for and their use is problematic * It's unclear what the latter are needed for and their use is problematic
@ -465,6 +466,27 @@ void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
lua_settable(L, objectstable); lua_settable(L, objectstable);
} }
void ScriptApiBase::addObjectByGuid(ServerActiveObject *cobj)
{
SCRIPTAPI_PRECHECKHEADER
assert(getType() == ScriptingType::Server);
// Create object on stack
ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
int object = lua_gettop(L);
// Get core.objects_by_guid table
lua_getglobal(L, "core");
lua_getfield(L, -1, "objects_by_guid");
luaL_checktype(L, -1, LUA_TTABLE);
int objectstable = lua_gettop(L);
// objects_by_guid[GUID] = object
lua_pushstring(L, cobj->getGuid().c_str()); // Push GUID
lua_pushvalue(L, object); // Copy object to top of stack
lua_settable(L, objectstable);
}
void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj) void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
@ -472,6 +494,7 @@ void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
// Get core.object_refs table // Get core.object_refs table
lua_getglobal(L, "core"); lua_getglobal(L, "core");
int core = lua_gettop(L);
lua_getfield(L, -1, "object_refs"); lua_getfield(L, -1, "object_refs");
luaL_checktype(L, -1, LUA_TTABLE); luaL_checktype(L, -1, LUA_TTABLE);
int objectstable = lua_gettop(L); int objectstable = lua_gettop(L);
@ -484,7 +507,17 @@ void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
lua_pop(L, 1); // pop object lua_pop(L, 1); // pop object
// Set object_refs[id] = nil // Set object_refs[id] = nil
lua_pushnumber(L, cobj->getId()); // Push id lua_pushnumber(L, cobj->getId()); // Push GUID
lua_pushnil(L);
lua_settable(L, objectstable);
// Get core.objects_by_guid
lua_getfield(L, core, "objects_by_guid");
luaL_checktype(L, -1, LUA_TTABLE);
objectstable = lua_gettop(L);
// Set objects_by_guid[GUID] = nil
lua_pushstring(L, cobj->getGuid().c_str()); // Push GUID
lua_pushnil(L); lua_pushnil(L);
lua_settable(L, objectstable); lua_settable(L, objectstable);
} }

View File

@ -100,6 +100,7 @@ public:
/* object */ /* object */
void addObjectReference(ServerActiveObject *cobj); void addObjectReference(ServerActiveObject *cobj);
void addObjectByGuid(ServerActiveObject *cobj);
void removeObjectReference(ServerActiveObject *cobj); void removeObjectReference(ServerActiveObject *cobj);
ScriptingType getType() { return m_type; } ScriptingType getType() { return m_type; }

View File

@ -106,6 +106,21 @@ int ObjectRef::l_remove(lua_State *L)
return 0; return 0;
} }
// get_guid()
int ObjectRef::l_get_guid(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkObject<ObjectRef>(L, 1);
ServerActiveObject *sao = getobject(ref);
if (sao == nullptr)
return 0;
const std::string &guid = sao->getGuid();
lua_pushstring(L, guid.c_str());
return 1;
}
// get_pos(self) // get_pos(self)
int ObjectRef::l_get_pos(lua_State *L) int ObjectRef::l_get_pos(lua_State *L)
{ {
@ -1120,6 +1135,25 @@ int ObjectRef::l_set_sprite(lua_State *L)
return 0; return 0;
} }
// set_guid(self, guid)
int ObjectRef::l_set_guid(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkObject<ObjectRef>(L, 1);
LuaEntitySAO *entitysao = getluaobject(ref);
if (entitysao == nullptr)
return 0;
std::string guid = readParam<std::string>(L, 2, "");
if (!guid.empty())
lua_pushboolean(L, entitysao->setGuid(guid));
else
lua_pushboolean(L, false);
return 1;
}
// DEPRECATED // DEPRECATED
// get_entity_name(self) // get_entity_name(self)
int ObjectRef::l_get_entity_name(lua_State *L) int ObjectRef::l_get_entity_name(lua_State *L)
@ -2632,6 +2666,7 @@ const char ObjectRef::className[] = "ObjectRef";
luaL_Reg ObjectRef::methods[] = { luaL_Reg ObjectRef::methods[] = {
// ServerActiveObject // ServerActiveObject
luamethod(ObjectRef, remove), luamethod(ObjectRef, remove),
luamethod(ObjectRef, get_guid),
luamethod_aliased(ObjectRef, get_pos, getpos), luamethod_aliased(ObjectRef, get_pos, getpos),
luamethod_aliased(ObjectRef, set_pos, setpos), luamethod_aliased(ObjectRef, set_pos, setpos),
luamethod(ObjectRef, add_pos), luamethod(ObjectRef, add_pos),
@ -2679,6 +2714,7 @@ luaL_Reg ObjectRef::methods[] = {
luamethod_aliased(ObjectRef, set_texture_mod, settexturemod), luamethod_aliased(ObjectRef, set_texture_mod, settexturemod),
luamethod(ObjectRef, get_texture_mod), luamethod(ObjectRef, get_texture_mod),
luamethod_aliased(ObjectRef, set_sprite, setsprite), luamethod_aliased(ObjectRef, set_sprite, setsprite),
luamethod(ObjectRef, set_guid),
luamethod(ObjectRef, get_entity_name), luamethod(ObjectRef, get_entity_name),
luamethod(ObjectRef, get_luaentity), luamethod(ObjectRef, get_luaentity),

View File

@ -67,6 +67,9 @@ private:
// remove(self) // remove(self)
static int l_remove(lua_State *L); static int l_remove(lua_State *L);
// get_guid()
static int l_get_guid(lua_State *L);
// get_pos(self) // get_pos(self)
static int l_get_pos(lua_State *L); static int l_get_pos(lua_State *L);
@ -200,6 +203,9 @@ private:
// set_sprite(self, start_frame, num_frames, framelength, select_x_by_camera) // set_sprite(self, start_frame, num_frames, framelength, select_x_by_camera)
static int l_set_sprite(lua_State *L); static int l_set_sprite(lua_State *L);
// set_guid(self, guid)
static int l_set_guid(lua_State *L);
// DEPRECATED // DEPRECATED
// get_entity_name(self) // get_entity_name(self)

View File

@ -76,6 +76,9 @@ ServerScripting::ServerScripting(Server* server):
lua_newtable(L); lua_newtable(L);
lua_setfield(L, -2, "object_refs"); lua_setfield(L, -2, "object_refs");
lua_newtable(L);
lua_setfield(L, -2, "objects_by_guid");
lua_newtable(L); lua_newtable(L);
lua_setfield(L, -2, "luaentities"); lua_setfield(L, -2, "luaentities");

View File

@ -85,6 +85,13 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, const std::string &d
m_rotation = rotation; m_rotation = rotation;
} }
LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, const std::string &name,
const std::string &state) :
UnitSAO(env, pos),
m_init_name(name), m_init_state(state)
{
}
LuaEntitySAO::~LuaEntitySAO() LuaEntitySAO::~LuaEntitySAO()
{ {
if(m_registered){ if(m_registered){
@ -113,6 +120,10 @@ void LuaEntitySAO::addedToEnvironment(u32 dtime_s)
// Activate entity, supplying serialized state // Activate entity, supplying serialized state
m_env->getScriptIface()-> m_env->getScriptIface()->
luaentity_Activate(m_id, m_init_state, dtime_s); luaentity_Activate(m_id, m_init_state, dtime_s);
// if Activate callback does not set guid, set it.
if (m_guid.empty()) {
getGuid();
}
} else { } else {
// It's an unknown object // It's an unknown object
// Use entitystring as infotext for debugging // Use entitystring as infotext for debugging
@ -428,6 +439,22 @@ u16 LuaEntitySAO::getHP() const
return m_hp; return m_hp;
} }
bool LuaEntitySAO::setGuid(std::string &guid)
{
if (m_guid.empty()) {
m_guid = guid;
return true;
}
return false;
}
GUId LuaEntitySAO::getGuid()
{
if (m_guid.empty()) {
m_guid = m_env->getGUIdGenerator().next(std::string("@"));
}
return m_guid;
}
void LuaEntitySAO::setVelocity(v3f velocity) void LuaEntitySAO::setVelocity(v3f velocity)
{ {
m_velocity = velocity; m_velocity = velocity;

View File

@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once #pragma once
#include "unit_sao.h" #include "unit_sao.h"
#include "guid.h"
class LuaEntitySAO : public UnitSAO class LuaEntitySAO : public UnitSAO
{ {
@ -30,11 +31,7 @@ public:
LuaEntitySAO(ServerEnvironment *env, v3f pos, const std::string &data); LuaEntitySAO(ServerEnvironment *env, v3f pos, const std::string &data);
// Used by the Lua API // Used by the Lua API
LuaEntitySAO(ServerEnvironment *env, v3f pos, const std::string &name, LuaEntitySAO(ServerEnvironment *env, v3f pos, const std::string &name,
const std::string &state) : const std::string &state);
UnitSAO(env, pos),
m_init_name(name), m_init_state(state)
{
}
~LuaEntitySAO(); ~LuaEntitySAO();
ActiveObjectType getType() const { return ACTIVEOBJECT_TYPE_LUAENTITY; } ActiveObjectType getType() const { return ACTIVEOBJECT_TYPE_LUAENTITY; }
@ -62,6 +59,8 @@ public:
void setHP(s32 hp, const PlayerHPChangeReason &reason); void setHP(s32 hp, const PlayerHPChangeReason &reason);
u16 getHP() const; u16 getHP() const;
bool setGuid(std::string &guid);
GUId getGuid() override;
/* LuaEntitySAO-specific */ /* LuaEntitySAO-specific */
void setVelocity(v3f velocity); void setVelocity(v3f velocity);
@ -95,6 +94,8 @@ private:
std::string m_init_state; std::string m_init_state;
bool m_registered = false; bool m_registered = false;
GUId m_guid;
v3f m_velocity; v3f m_velocity;
v3f m_acceleration; v3f m_acceleration;

View File

@ -30,6 +30,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, session_t p
UnitSAO(env_, v3f(0,0,0)), UnitSAO(env_, v3f(0,0,0)),
m_player(player_), m_player(player_),
m_peer_id_initial(peer_id_), m_peer_id_initial(peer_id_),
m_guid(player_->getName()),
m_is_singleplayer(is_singleplayer) m_is_singleplayer(is_singleplayer)
{ {
SANITY_CHECK(m_peer_id_initial != PEER_ID_INEXISTENT); SANITY_CHECK(m_peer_id_initial != PEER_ID_INEXISTENT);
@ -417,6 +418,11 @@ void PlayerSAO::setPlayerYaw(const float yaw)
UnitSAO::setRotation(rotation); UnitSAO::setRotation(rotation);
} }
GUId PlayerSAO::getGuid()
{
return m_guid;
}
void PlayerSAO::setFov(const float fov) void PlayerSAO::setFov(const float fov)
{ {
if (m_player && fov != m_fov) if (m_player && fov != m_fov)

View File

@ -93,6 +93,7 @@ public:
void addPos(const v3f &added_pos) override; void addPos(const v3f &added_pos) override;
void moveTo(v3f pos, bool continuous) override; void moveTo(v3f pos, bool continuous) override;
void setPlayerYaw(const float yaw); void setPlayerYaw(const float yaw);
GUId getGuid() override;
// Data should not be sent at player initialization // Data should not be sent at player initialization
void setPlayerYawAndSend(const float yaw); void setPlayerYawAndSend(const float yaw);
void setLookPitch(const float pitch); void setLookPitch(const float pitch);
@ -195,6 +196,7 @@ private:
RemotePlayer *m_player = nullptr; RemotePlayer *m_player = nullptr;
session_t m_peer_id_initial = 0; ///< only used to initialize RemotePlayer session_t m_peer_id_initial = 0; ///< only used to initialize RemotePlayer
GUId m_guid;
// Cheat prevention // Cheat prevention
LagPool m_dig_pool; LagPool m_dig_pool;

View File

@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_bloated.h" #include "irrlichttypes_bloated.h"
#include "activeobject.h" #include "activeobject.h"
#include "itemgroup.h" #include "itemgroup.h"
#include "guid.h"
#include "util/container.h" #include "util/container.h"
@ -160,6 +161,9 @@ public:
virtual u16 getHP() const virtual u16 getHP() const
{ return 0; } { return 0; }
// Returns always the same unique string for the same object.
virtual GUId getGuid() = 0;
virtual void setArmorGroups(const ItemGroupList &armor_groups) virtual void setArmorGroups(const ItemGroupList &armor_groups)
{} {}
virtual const ItemGroupList &getArmorGroups() const virtual const ItemGroupList &getArmorGroups() const
@ -235,6 +239,11 @@ public:
about handling it. about handling it.
*/ */
bool m_static_exists = false; bool m_static_exists = false;
/*
Set this to true when the staticdata needs to be saved even though it
looks like it did not change.
*/
bool m_force_write_staticdata = false;
/* /*
The block from which the object was loaded from, and in which The block from which the object was loaded from, and in which
a copy of the static data resides. a copy of the static data resides.

View File

@ -448,6 +448,8 @@ ServerEnvironment::ServerEnvironment(std::unique_ptr<ServerMap> map,
m_active_object_gauge = mb->addGauge( m_active_object_gauge = mb->addGauge(
"minetest_env_active_objects", "Number of active objects"); "minetest_env_active_objects", "Number of active objects");
m_guid_generator.setServerEnvironment(this);
} }
void ServerEnvironment::init() void ServerEnvironment::init()
@ -1889,6 +1891,8 @@ u16 ServerEnvironment::addActiveObjectRaw(std::unique_ptr<ServerActiveObject> ob
// Post-initialize object // Post-initialize object
// Note that this can change the value of isStaticAllowed() in case of LuaEntitySAO // Note that this can change the value of isStaticAllowed() in case of LuaEntitySAO
object->addedToEnvironment(dtime_s); object->addedToEnvironment(dtime_s);
// After post-initialize, GUID is known
m_script->addObjectByGuid(object);
// Activate object // Activate object
if (object->m_static_exists) if (object->m_static_exists)
@ -2199,7 +2203,9 @@ void ServerEnvironment::deactivateFarObjects(const bool _force_delete)
While changes are always saved, blocks are only marked as modified While changes are always saved, blocks are only marked as modified
if the object has moved or different staticdata. (see above) if the object has moved or different staticdata. (see above)
*/ */
bool shall_be_written = (!stays_in_same_block || data_changed); bool shall_be_written = (!stays_in_same_block || data_changed ||
obj->m_force_write_staticdata);
obj->m_force_write_staticdata = false;
u32 reason = shall_be_written ? MOD_REASON_STATIC_DATA_CHANGED : MOD_REASON_UNKNOWN; u32 reason = shall_be_written ? MOD_REASON_STATIC_DATA_CHANGED : MOD_REASON_UNKNOWN;
// Delete old static object // Delete old static object

View File

@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "activeobject.h" #include "activeobject.h"
#include "environment.h" #include "environment.h"
#include "servermap.h" #include "servermap.h"
#include "guid.h"
#include "map.h"
#include "settings.h" #include "settings.h"
#include "server/activeobjectmgr.h" #include "server/activeobjectmgr.h"
#include "util/numeric.h" #include "util/numeric.h"
@ -238,6 +240,9 @@ public:
float getSendRecommendedInterval() float getSendRecommendedInterval()
{ return m_recommended_send_interval; } { return m_recommended_send_interval; }
GUIdGenerator & getGUIdGenerator()
{ return m_guid_generator; }
// Save players // Save players
void saveLoadedPlayers(bool force = false); void saveLoadedPlayers(bool force = false);
void savePlayer(RemotePlayer *player); void savePlayer(RemotePlayer *player);
@ -463,6 +468,10 @@ private:
server::ActiveObjectMgr m_ao_manager; server::ActiveObjectMgr m_ao_manager;
// on_mapblocks_changed map event receiver // on_mapblocks_changed map event receiver
OnMapblocksChangedReceiver m_on_mapblocks_changed_receiver; OnMapblocksChangedReceiver m_on_mapblocks_changed_receiver;
// Generator for luaentity guids
GUIdGenerator m_guid_generator;
// World path
const std::string m_path_world;
// Outgoing network message buffer for active objects // Outgoing network message buffer for active objects
std::queue<ActiveObjectMessage> m_active_object_messages; std::queue<ActiveObjectMessage> m_active_object_messages;
// Some timers // Some timers

View File

@ -29,4 +29,5 @@ public:
virtual bool getCollisionBox(aabb3f *toset) const { return false; } virtual bool getCollisionBox(aabb3f *toset) const { return false; }
virtual bool getSelectionBox(aabb3f *toset) const { return false; } virtual bool getSelectionBox(aabb3f *toset) const { return false; }
virtual bool collideWithObjects() const { return false; } virtual bool collideWithObjects() const { return false; }
virtual std::string getGuid() {return "";}
}; };

View File

@ -31,18 +31,18 @@ public:
void runTests(IGameDef *gamedef); void runTests(IGameDef *gamedef);
void testMove(ServerActiveObject *obj, IGameDef *gamedef); void testMove(MockServerActiveObject *obj, IGameDef *gamedef);
void testMoveFillStack(ServerActiveObject *obj, IGameDef *gamedef); void testMoveFillStack(MockServerActiveObject *obj, IGameDef *gamedef);
void testMoveSomewhere(ServerActiveObject *obj, IGameDef *gamedef); void testMoveSomewhere(MockServerActiveObject *obj, IGameDef *gamedef);
void testMoveUnallowed(ServerActiveObject *obj, IGameDef *gamedef); void testMoveUnallowed(MockServerActiveObject *obj, IGameDef *gamedef);
void testMovePartial(ServerActiveObject *obj, IGameDef *gamedef); void testMovePartial(MockServerActiveObject *obj, IGameDef *gamedef);
void testSwap(ServerActiveObject *obj, IGameDef *gamedef); void testSwap(MockServerActiveObject *obj, IGameDef *gamedef);
void testSwapFromUnallowed(ServerActiveObject *obj, IGameDef *gamedef); void testSwapFromUnallowed(MockServerActiveObject *obj, IGameDef *gamedef);
void testSwapToUnallowed(ServerActiveObject *obj, IGameDef *gamedef); void testSwapToUnallowed(MockServerActiveObject *obj, IGameDef *gamedef);
void testCallbacks(ServerActiveObject *obj, Server *server); void testCallbacks(MockServerActiveObject *obj, Server *server);
void testCallbacksSwap(ServerActiveObject *obj, Server *server); void testCallbacksSwap(MockServerActiveObject *obj, Server *server);
}; };
static TestMoveAction g_test_instance; static TestMoveAction g_test_instance;
@ -97,7 +97,7 @@ static void apply_action(const char *s, InventoryManager *inv, ServerActiveObjec
delete action; delete action;
} }
void TestMoveAction::testMove(ServerActiveObject *obj, IGameDef *gamedef) void TestMoveAction::testMove(MockServerActiveObject *obj, IGameDef *gamedef)
{ {
MockInventoryManager inv(gamedef); MockInventoryManager inv(gamedef);
@ -110,7 +110,7 @@ void TestMoveAction::testMove(ServerActiveObject *obj, IGameDef *gamedef)
UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:stone 20"); UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:stone 20");
} }
void TestMoveAction::testMoveFillStack(ServerActiveObject *obj, IGameDef *gamedef) void TestMoveAction::testMoveFillStack(MockServerActiveObject *obj, IGameDef *gamedef)
{ {
MockInventoryManager inv(gamedef); MockInventoryManager inv(gamedef);
@ -130,7 +130,7 @@ void TestMoveAction::testMoveFillStack(ServerActiveObject *obj, IGameDef *gamede
UASSERT(list->getItem(1).getItemString() == "default:stone 200"); UASSERT(list->getItem(1).getItemString() == "default:stone 200");
} }
void TestMoveAction::testMoveSomewhere(ServerActiveObject *obj, IGameDef *gamedef) void TestMoveAction::testMoveSomewhere(MockServerActiveObject *obj, IGameDef *gamedef)
{ {
MockInventoryManager inv(gamedef); MockInventoryManager inv(gamedef);
@ -146,7 +146,7 @@ void TestMoveAction::testMoveSomewhere(ServerActiveObject *obj, IGameDef *gamede
UASSERT(inv.p2.getList("main")->getItem(2).getItemString() == "default:stone 99"); UASSERT(inv.p2.getList("main")->getItem(2).getItemString() == "default:stone 99");
} }
void TestMoveAction::testMoveUnallowed(ServerActiveObject *obj, IGameDef *gamedef) void TestMoveAction::testMoveUnallowed(MockServerActiveObject *obj, IGameDef *gamedef)
{ {
MockInventoryManager inv(gamedef); MockInventoryManager inv(gamedef);
@ -159,7 +159,7 @@ void TestMoveAction::testMoveUnallowed(ServerActiveObject *obj, IGameDef *gamede
UASSERT(inv.p2.getList("main")->getItem(0).empty()) UASSERT(inv.p2.getList("main")->getItem(0).empty())
} }
void TestMoveAction::testMovePartial(ServerActiveObject *obj, IGameDef *gamedef) void TestMoveAction::testMovePartial(MockServerActiveObject *obj, IGameDef *gamedef)
{ {
MockInventoryManager inv(gamedef); MockInventoryManager inv(gamedef);
@ -173,7 +173,7 @@ void TestMoveAction::testMovePartial(ServerActiveObject *obj, IGameDef *gamedef)
UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:takeput_max_5 5"); UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:takeput_max_5 5");
} }
void TestMoveAction::testSwap(ServerActiveObject *obj, IGameDef *gamedef) void TestMoveAction::testSwap(MockServerActiveObject *obj, IGameDef *gamedef)
{ {
MockInventoryManager inv(gamedef); MockInventoryManager inv(gamedef);
@ -186,7 +186,7 @@ void TestMoveAction::testSwap(ServerActiveObject *obj, IGameDef *gamedef)
UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:stone 50"); UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:stone 50");
} }
void TestMoveAction::testSwapFromUnallowed(ServerActiveObject *obj, IGameDef *gamedef) void TestMoveAction::testSwapFromUnallowed(MockServerActiveObject *obj, IGameDef *gamedef)
{ {
MockInventoryManager inv(gamedef); MockInventoryManager inv(gamedef);
@ -199,7 +199,7 @@ void TestMoveAction::testSwapFromUnallowed(ServerActiveObject *obj, IGameDef *ga
UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:brick 60"); UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:brick 60");
} }
void TestMoveAction::testSwapToUnallowed(ServerActiveObject *obj, IGameDef *gamedef) void TestMoveAction::testSwapToUnallowed(MockServerActiveObject *obj, IGameDef *gamedef)
{ {
MockInventoryManager inv(gamedef); MockInventoryManager inv(gamedef);
@ -230,7 +230,7 @@ static bool check_function(lua_State *L, bool expect_swap)
return ok; return ok;
} }
void TestMoveAction::testCallbacks(ServerActiveObject *obj, Server *server) void TestMoveAction::testCallbacks(MockServerActiveObject *obj, Server *server)
{ {
server->m_inventory_mgr = std::make_unique<MockInventoryManager>(server); server->m_inventory_mgr = std::make_unique<MockInventoryManager>(server);
MockInventoryManager &inv = *(MockInventoryManager *)server->getInventoryMgr(); MockInventoryManager &inv = *(MockInventoryManager *)server->getInventoryMgr();
@ -246,7 +246,7 @@ void TestMoveAction::testCallbacks(ServerActiveObject *obj, Server *server)
server->m_inventory_mgr.reset(); server->m_inventory_mgr.reset();
} }
void TestMoveAction::testCallbacksSwap(ServerActiveObject *obj, Server *server) void TestMoveAction::testCallbacksSwap(MockServerActiveObject *obj, Server *server)
{ {
server->m_inventory_mgr = std::make_unique<MockInventoryManager>(server); server->m_inventory_mgr = std::make_unique<MockInventoryManager>(server);
MockInventoryManager &inv = *(MockInventoryManager *)server->getInventoryMgr(); MockInventoryManager &inv = *(MockInventoryManager *)server->getInventoryMgr();

View File

@ -26,7 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "profiler.h" #include "profiler.h"
class TestServerActiveObjectMgr : public TestBase class TestServerActiveObjectMgr : public TestBase
{ {
public: public: