core.registered_nodes = {}
core.registered_items = {}
+core.object_refs = {}
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
-- 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
* 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
-----------------
### 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)`
{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
{
ClientActiveObject* obj =
ClientActiveObject::create((ActiveObjectType) type, m_client, this);
+
if(obj == NULL)
{
infostream<<"ClientEnvironment::addActiveObject(): "
obj->setId(id);
+ if (m_client->modsLoaded())
+ m_client->getScript()->addObjectReference(dynamic_cast<ActiveObject*>(obj));
+
try
{
obj->initialize(init_data);
{
// 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
} 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;
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)
{
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);
} 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");
#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"
* 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
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;
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
<< ", this is probably a bug." << std::endl;
}
}
-
void ScriptApiBase::pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason &reason)
{
if (reason.hasLuaReference())
class IGameDef;
class Environment;
class GUIEngine;
+class ActiveObject;
class ServerActiveObject;
struct PlayerHPChangeReason;
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();
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);
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);
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;
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;
{
ClientObjectRef *ref = checkobject(L, 1);
ClientActiveObject *cao = get_cao(ref);
+ if (! cao)
+ return 0;
push_v3f(L, cao->getPosition() / BS);
return 1;
}
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
+ if (! gcao)
+ return 0;
push_v3f(L, gcao->getVelocity() / BS);
return 1;
}
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
+ if (! gcao)
+ return 0;
push_v3f(L, gcao->getAcceleration() / BS);
return 1;
}
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
+ if (! gcao)
+ return 0;
push_v3f(L, gcao->getRotation());
return 1;
}
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
+ if (! gcao)
+ return 0;
lua_pushboolean(L, gcao->isPlayer());
return 1;
}
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
+ if (! gcao)
+ return 0;
lua_pushboolean(L, gcao->isLocalPlayer());
return 1;
}
{
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;
}
{
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;
}
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;
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);
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;
{
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;
{
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);
{
ClientObjectRef *ref = checkobject(L, 1);
GenericCAO *gcao = get_generic_cao(ref, L);
+ if (! gcao)
+ return 0;
lua_pushnumber(L, gcao->getHp());
return 1;
}
{
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;
{
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;
{
ClientObjectRef *ref = checkobject(L, 1);
ClientActiveObject *cao = get_cao(ref);
+ if (! cao)
+ return 0;
getClient(L)->getEnv().removeActiveObject(cao->getId());
return 0;
{
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);
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)
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));
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:
ClientEnvironment &env = getClient(L)->getEnv();
ClientActiveObject *obj = env.getGenericCAO(player->getCAO()->getId());
- ClientObjectRef::create(L, obj);
+ push_objectRef(L, obj->getId());
return 1;
}
// 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())
}
// 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);
// 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())
// 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())