Include tile definitions in get_node_def; Client-side minetest.object_refs table

wsc-dfc
Elias Fleckenstein 2021-05-11 14:07:30 +02:00
parent c86dcd0f68
commit 4f613bbf51
15 changed files with 213 additions and 43 deletions

View File

@ -110,3 +110,4 @@ core.registered_on_object_hp_change, core.register_on_object_hp_change = make_re
core.registered_nodes = {}
core.registered_items = {}
core.object_refs = {}

View File

@ -785,3 +785,12 @@ end
function core.is_nan(number)
return number ~= number
end
function core.inventorycube(img1, img2, img3)
img2 = img2 or img1
img3 = img3 or img1
return "[inventorycube"
.. "{" .. img1:gsub("%^", "&")
.. "{" .. img2:gsub("%^", "&")
.. "{" .. img3:gsub("%^", "&")
end

View File

@ -15,15 +15,6 @@ end
-- Item definition helpers
--
function core.inventorycube(img1, img2, img3)
img2 = img2 or img1
img3 = img3 or img1
return "[inventorycube"
.. "{" .. img1:gsub("%^", "&")
.. "{" .. img2:gsub("%^", "&")
.. "{" .. img3:gsub("%^", "&")
end
function core.dir_to_facedir(dir, is6d)
--account for y if requested
if is6d and math.abs(dir.y) > math.abs(dir.x) and math.abs(dir.y) > math.abs(dir.z) then

View File

@ -934,6 +934,8 @@ Call these functions only at load time!
* Convert between two privilege representations
### Client Environment
* `minetest.object_refs`
* Map of object references, indexed by active object id
* `minetest.get_player_names()`
* Returns list of player names on server (nil if CSM_RF_READ_PLAYERINFO is enabled by server)
* `minetest.get_objects_inside_radius(pos, radius)`: returns a list of
@ -1454,6 +1456,8 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
-----------------
### Definitions
* `minetest.inventorycube(img1, img2, img3)`
* Returns a string for making an image of a cube (useful as an item image)
* `minetest.get_node_def(nodename)`
* Returns [node definition](#node-definition) table of `nodename`
* `minetest.get_item_def(itemstring)`
@ -1465,10 +1469,67 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
{light_source=minetest.LIGHT_MAX})`
* Doesnt really work yet an causes strange bugs, I'm working to make is better
#### Tile definition
* `"image.png"`
* `{name="image.png", animation={Tile Animation definition}}`
* `{name="image.png", backface_culling=bool, align_style="node"/"world"/"user", scale=int}`
* backface culling enabled by default for most nodes
* align style determines whether the texture will be rotated with the node
or kept aligned with its surroundings. "user" means that client
setting will be used, similar to `glasslike_framed_optional`.
Note: supported by solid nodes and nodeboxes only.
* scale is used to make texture span several (exactly `scale`) nodes,
instead of just one, in each direction. Works for world-aligned
textures only.
Note that as the effect is applied on per-mapblock basis, `16` should
be equally divisible by `scale` or you may get wrong results.
* `{name="image.png", color=ColorSpec}`
* the texture's color will be multiplied with this color.
* the tile's color overrides the owning node's color in all cases.
##### Tile definition
{
type = "vertical_frames",
aspect_w = 16,
-- Width of a frame in pixels
aspect_h = 16,
-- Height of a frame in pixels
length = 3.0,
-- Full loop length
}
{
type = "sheet_2d",
frames_w = 5,
-- Width in number of frames
frames_h = 3,
-- Height in number of frames
frame_length = 0.5,
-- Length of a single frame
}
#### Node Definition
```lua
{
tiles = {tile definition 1, def2, def3, def4, def5, def6},
-- Textures of node; +Y, -Y, +X, -X, +Z, -Z
overlay_tiles = {tile definition 1, def2, def3, def4, def5, def6},
-- Same as `tiles`, but these textures are drawn on top of the base
-- tiles. This is used to colorize only specific parts of the
-- texture. If the texture name is an empty string, that overlay is not
-- drawn
special_tiles = {tile definition 1, Tile definition 2},
-- Special textures of node; used rarely.
has_on_construct = bool, -- Whether the node has the on_construct callback defined
has_on_destruct = bool, -- Whether the node has the on_destruct callback defined
has_after_destruct = bool, -- Whether the node has the after_destruct callback defined

View File

@ -352,6 +352,7 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
{
ClientActiveObject* obj =
ClientActiveObject::create((ActiveObjectType) type, m_client, this);
if(obj == NULL)
{
infostream<<"ClientEnvironment::addActiveObject(): "
@ -362,6 +363,9 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
obj->setId(id);
if (m_client->modsLoaded())
m_client->getScript()->addObjectReference(dynamic_cast<ActiveObject*>(obj));
try
{
obj->initialize(init_data);
@ -394,9 +398,14 @@ void ClientEnvironment::removeActiveObject(u16 id)
{
// Get current attachment childs to detach them visually
std::unordered_set<int> attachment_childs;
if (auto *obj = getActiveObject(id))
auto *obj = getActiveObject(id);
if (obj) {
attachment_childs = obj->getAttachmentChildIds();
if (m_client->modsLoaded())
m_client->getScript()->removeObjectReference(dynamic_cast<ActiveObject*>(obj));
}
m_ao_manager.removeObject(id);
// Perform a proper detach in Irrlicht

View File

@ -734,7 +734,7 @@ bool Game::connectToServer(const GameStartData &start_data,
} else {
wait_time += dtime;
// Only time out if we aren't waiting for the server we started
if (!start_data.isSinglePlayer() && wait_time > 10) {
if (!start_data.local_server && !start_data.isSinglePlayer() && wait_time > 10) {
*error_message = "Connection timed out.";
errorstream << *error_message << std::endl;
break;

View File

@ -515,6 +515,35 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
return tiledef;
}
/******************************************************************************/
void push_tiledef(lua_State *L, TileDef tiledef)
{
lua_newtable(L);
setstringfield(L, -1, "name", tiledef.name);
setboolfield(L, -1, "backface_culling", tiledef.backface_culling);
setboolfield(L, -1, "tileable_horizontal", tiledef.tileable_horizontal);
setboolfield(L, -1, "tileable_vertical", tiledef.tileable_vertical);
std::string align_style;
switch (tiledef.align_style) {
case ALIGN_STYLE_USER_DEFINED:
align_style = "user";
break;
case ALIGN_STYLE_WORLD:
align_style = "world";
break;
default:
align_style = "node";
}
setstringfield(L, -1, "align_style", align_style);
setintfield(L, -1, "scale", tiledef.scale);
if (tiledef.has_color) {
push_ARGB8(L, tiledef.color);
lua_setfield(L, -2, "color");
}
push_animation_definition(L, tiledef.animation);
lua_setfield(L, -2, "animation");
}
/******************************************************************************/
void read_content_features(lua_State *L, ContentFeatures &f, int index)
{
@ -835,9 +864,32 @@ void push_content_features(lua_State *L, const ContentFeatures &c)
std::string drawtype(ScriptApiNode::es_DrawType[(int)c.drawtype].str);
std::string liquid_type(ScriptApiNode::es_LiquidType[(int)c.liquid_type].str);
/* Missing "tiles" because I don't see a usecase (at least not yet). */
lua_newtable(L);
// tiles
lua_newtable(L);
for (int i = 0; i < 6; i++) {
push_tiledef(L, c.tiledef[i]);
lua_rawseti(L, -2, i + 1);
}
lua_setfield(L, -2, "tiles");
// overlay_tiles
lua_newtable(L);
for (int i = 0; i < 6; i++) {
push_tiledef(L, c.tiledef_overlay[i]);
lua_rawseti(L, -2, i + 1);
}
lua_setfield(L, -2, "overlay_tiles");
// special_tiles
lua_newtable(L);
for (int i = 0; i < CF_SPECIAL_COUNT; i++) {
push_tiledef(L, c.tiledef_special[i]);
lua_rawseti(L, -2, i + 1);
}
lua_setfield(L, -2, "special_tiles");
lua_pushboolean(L, c.has_on_construct);
lua_setfield(L, -2, "has_on_construct");
lua_pushboolean(L, c.has_on_destruct);
@ -1886,14 +1938,7 @@ void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm,
} else if (pointed.type == POINTEDTHING_OBJECT) {
lua_pushstring(L, "object");
lua_setfield(L, -2, "type");
if (csm) {
#ifndef SERVER
ClientObjectRef::create(L, pointed.object_id);
#endif
} else {
push_objectRef(L, pointed.object_id);
}
push_objectRef(L, pointed.object_id);
lua_setfield(L, -2, "ref");
} else {
lua_pushstring(L, "nothing");

View File

@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_internal.h"
#include "cpp_api/s_security.h"
#include "lua_api/l_object.h"
#include "lua_api/l_clientobject.h"
#include "common/c_converter.h"
#include "server/player_sao.h"
#include "filesys.h"
@ -354,13 +355,16 @@ void ScriptApiBase::setOriginFromTableRaw(int index, const char *fxn)
* since we lose control over the ref and the contained pointer.
*/
void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
void ScriptApiBase::addObjectReference(ActiveObject *cobj)
{
SCRIPTAPI_PRECHECKHEADER
//infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
// Create object on stack
ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
if (m_type == ScriptingType::Client)
ClientObjectRef::create(L, dynamic_cast<ClientActiveObject *>(cobj));
else
ObjectRef::create(L, dynamic_cast<ServerActiveObject *>(cobj)); // Puts ObjectRef (as userdata) on stack
int object = lua_gettop(L);
// Get core.object_refs table
@ -375,7 +379,7 @@ void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
lua_settable(L, objectstable);
}
void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
void ScriptApiBase::removeObjectReference(ActiveObject *cobj)
{
SCRIPTAPI_PRECHECKHEADER
//infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
@ -390,7 +394,10 @@ void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
lua_pushnumber(L, cobj->getId()); // Push id
lua_gettable(L, objectstable);
// Set object reference to NULL
ObjectRef::set_null(L);
if (m_type == ScriptingType::Client)
ClientObjectRef::set_null(L);
else
ObjectRef::set_null(L);
lua_pop(L, 1); // pop object
// Set object_refs[id] = nil
@ -413,7 +420,6 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
<< ", this is probably a bug." << std::endl;
}
}
void ScriptApiBase::pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason &reason)
{
if (reason.hasLuaReference())

View File

@ -73,6 +73,7 @@ class Game;
class IGameDef;
class Environment;
class GUIEngine;
class ActiveObject;
class ServerActiveObject;
struct PlayerHPChangeReason;
@ -99,8 +100,8 @@ public:
RunCallbacksMode mode, const char *fxn);
/* object */
void addObjectReference(ServerActiveObject *cobj);
void removeObjectReference(ServerActiveObject *cobj);
void addObjectReference(ActiveObject *cobj);
void removeObjectReference(ActiveObject *cobj);
IGameDef *getGameDef() { return m_gamedef; }
Server* getServer();

View File

@ -302,7 +302,7 @@ void ScriptApiClient::on_object_properties_change(s16 id)
lua_getfield(L, -1, "registered_on_object_properties_change");
// Push data
ClientObjectRef::create(L, id);
push_objectRef(L, id);
// Call functions
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
@ -317,7 +317,7 @@ void ScriptApiClient::on_object_hp_change(s16 id)
lua_getfield(L, -1, "registered_on_object_hp_change");
// Push data
ClientObjectRef::create(L, id);
push_objectRef(L, id);
// Call functions
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);

View File

@ -520,7 +520,7 @@ int ModApiClient::l_get_objects_inside_radius(lua_State *L)
int i = 0;
lua_createtable(L, objs.size(), 0);
for (const auto obj : objs) {
ClientObjectRef::create(L, obj.obj); // TODO: getObjectRefOrCreate
push_objectRef(L, obj.obj->getId());
lua_rawseti(L, -2, ++i);
}
return 1;

View File

@ -48,6 +48,8 @@ ClientActiveObject *ClientObjectRef::get_cao(ClientObjectRef *ref)
GenericCAO *ClientObjectRef::get_generic_cao(ClientObjectRef *ref, lua_State *L)
{
ClientActiveObject *obj = get_cao(ref);
if (! obj)
return nullptr;
ClientEnvironment &env = getClient(L)->getEnv();
GenericCAO *gcao = env.getGenericCAO(obj->getId());
return gcao;
@ -57,6 +59,8 @@ int ClientObjectRef::l_get_pos(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
ClientActiveObject *cao = get_cao(ref);
if (! cao)
return 0;
push_v3f(L, cao->getPosition() / BS);
return 1;
}
@ -65,6 +69,8 @@ int ClientObjectRef::l_get_velocity(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
push_v3f(L, gcao->getVelocity() / BS);
return 1;
}
@ -73,6 +79,8 @@ int ClientObjectRef::l_get_acceleration(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
push_v3f(L, gcao->getAcceleration() / BS);
return 1;
}
@ -81,6 +89,8 @@ int ClientObjectRef::l_get_rotation(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
push_v3f(L, gcao->getRotation());
return 1;
}
@ -89,6 +99,8 @@ int ClientObjectRef::l_is_player(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
lua_pushboolean(L, gcao->isPlayer());
return 1;
}
@ -97,6 +109,8 @@ int ClientObjectRef::l_is_local_player(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
lua_pushboolean(L, gcao->isLocalPlayer());
return 1;
}
@ -105,6 +119,8 @@ int ClientObjectRef::l_get_name(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
lua_pushstring(L, gcao->getName().c_str());
return 1;
}
@ -113,7 +129,12 @@ int ClientObjectRef::l_get_attach(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
create(L, gcao->getParent());
if (! gcao)
return 0;
ClientActiveObject *parent = gcao->getParent();
if (! parent)
return 0;
push_objectRef(L, parent->getId());
return 1;
}
@ -122,6 +143,8 @@ int ClientObjectRef::l_get_nametag(lua_State *L)
log_deprecated(L,"Deprecated call to get_nametag, use get_properties().nametag instead");
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
ObjectProperties *props = gcao->getProperties();
lua_pushstring(L, props->nametag.c_str());
return 1;
@ -132,6 +155,8 @@ int ClientObjectRef::l_get_item_textures(lua_State *L)
log_deprecated(L,"Deprecated call to get_item_textures, use get_properties().textures instead");
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
ObjectProperties *props = gcao->getProperties();
lua_newtable(L);
@ -146,6 +171,8 @@ int ClientObjectRef::l_get_max_hp(lua_State *L)
log_deprecated(L,"Deprecated call to get_max_hp, use get_properties().hp_max instead");
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
ObjectProperties *props = gcao->getProperties();
lua_pushnumber(L, props->hp_max);
return 1;
@ -155,6 +182,8 @@ int ClientObjectRef::l_get_properties(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
ObjectProperties *prop = gcao->getProperties();
push_object_properties(L, prop);
return 1;
@ -164,6 +193,8 @@ int ClientObjectRef::l_set_properties(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
ObjectProperties prop = *gcao->getProperties();
read_object_properties(L, 2, nullptr, &prop, getClient(L)->idef());
gcao->setProperties(prop);
@ -174,6 +205,8 @@ int ClientObjectRef::l_get_hp(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
lua_pushnumber(L, gcao->getHp());
return 1;
}
@ -182,6 +215,8 @@ int ClientObjectRef::l_punch(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
PointedThing pointed(gcao->getId(), v3f(0, 0, 0), v3s16(0, 0, 0), 0);
getClient(L)->interact(INTERACT_START_DIGGING, pointed);
return 0;
@ -191,6 +226,8 @@ int ClientObjectRef::l_rightclick(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
PointedThing pointed(gcao->getId(), v3f(0, 0, 0), v3s16(0, 0, 0), 0);
getClient(L)->interact(INTERACT_PLACE, pointed);
return 0;
@ -200,6 +237,8 @@ int ClientObjectRef::l_remove(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
ClientActiveObject *cao = get_cao(ref);
if (! cao)
return 0;
getClient(L)->getEnv().removeActiveObject(cao->getId());
return 0;
@ -209,6 +248,8 @@ int ClientObjectRef::l_set_nametag_images(lua_State *L)
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
if (! gcao)
return 0;
gcao->nametag_images.clear();
if(lua_istable(L, 2)){
lua_pushnil(L);
@ -228,12 +269,10 @@ ClientObjectRef::ClientObjectRef(ClientActiveObject *object) : m_object(object)
void ClientObjectRef::create(lua_State *L, ClientActiveObject *object)
{
if (object) {
ClientObjectRef *o = new ClientObjectRef(object);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
}
ClientObjectRef *o = new ClientObjectRef(object);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
}
void ClientObjectRef::create(lua_State *L, s16 id)
@ -241,6 +280,12 @@ void ClientObjectRef::create(lua_State *L, s16 id)
create(L, ((ClientEnvironment *)getEnv(L))->getActiveObject(id));
}
void ClientObjectRef::set_null(lua_State *L)
{
ClientObjectRef *obj = checkobject(L, -1);
obj->m_object = nullptr;
}
int ClientObjectRef::gc_object(lua_State *L)
{
ClientObjectRef *obj = *(ClientObjectRef **)(lua_touserdata(L, 1));

View File

@ -35,6 +35,8 @@ public:
static void create(lua_State *L, ClientActiveObject *object);
static void create(lua_State *L, s16 id);
static void set_null(lua_State *L);
static ClientObjectRef *checkobject(lua_State *L, int narg);
private:

View File

@ -483,7 +483,7 @@ int LuaLocalPlayer::l_get_object(lua_State *L)
ClientEnvironment &env = getClient(L)->getEnv();
ClientActiveObject *obj = env.getGenericCAO(player->getCAO()->getId());
ClientObjectRef::create(L, obj);
push_objectRef(L, obj->getId());
return 1;
}

View File

@ -1170,7 +1170,7 @@ void ServerEnvironment::clearObjects(ClearObjectsMode mode)
// Tell the object about removal
obj->removingFromEnvironment();
// Deregister in scripting api
m_script->removeObjectReference(obj);
m_script->removeObjectReference(dynamic_cast<ActiveObject *>(obj));
// Delete active object
if (obj->environmentDeletes())
@ -1736,7 +1736,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
}
// Register reference in scripting api (must be done before post-init)
m_script->addObjectReference(object);
m_script->addObjectReference(dynamic_cast<ActiveObject *>(object));
// Post-initialize object
object->addedToEnvironment(dtime_s);
@ -1826,7 +1826,7 @@ void ServerEnvironment::removeRemovedObjects()
// Tell the object about removal
obj->removingFromEnvironment();
// Deregister in scripting api
m_script->removeObjectReference(obj);
m_script->removeObjectReference(dynamic_cast<ActiveObject *>(obj));
// Delete
if (obj->environmentDeletes())
@ -2091,7 +2091,7 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
// Tell the object about removal
obj->removingFromEnvironment();
// Deregister in scripting api
m_script->removeObjectReference(obj);
m_script->removeObjectReference(dynamic_cast<ActiveObject *>(obj));
// Delete active object
if (obj->environmentDeletes())