+
+void read_hud_element(lua_State *L, HudElement *elem)
+{
+ elem->type = (HudElementType)getenumfield(L, 2, "hud_elem_type",
+ es_HudElementType, HUD_ELEM_TEXT);
+
+ lua_getfield(L, 2, "position");
+ elem->pos = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
+ lua_pop(L, 1);
+
+ lua_getfield(L, 2, "scale");
+ elem->scale = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
+ lua_pop(L, 1);
+
+ lua_getfield(L, 2, "size");
+ elem->size = lua_istable(L, -1) ? read_v2s32(L, -1) : v2s32();
+ lua_pop(L, 1);
+
+ elem->name = getstringfield_default(L, 2, "name", "");
+ elem->text = getstringfield_default(L, 2, "text", "");
+ elem->number = getintfield_default(L, 2, "number", 0);
+ if (elem->type == HUD_ELEM_WAYPOINT)
+ // waypoints reuse the item field to store precision, item = precision + 1
+ elem->item = getintfield_default(L, 2, "precision", -1) + 1;
+ else
+ elem->item = getintfield_default(L, 2, "item", 0);
+ elem->dir = getintfield_default(L, 2, "direction", 0);
+ elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX,
+ getintfield_default(L, 2, "z_index", 0)));
+
+ // Deprecated, only for compatibility's sake
+ if (elem->dir == 0)
+ elem->dir = getintfield_default(L, 2, "dir", 0);
+
+ lua_getfield(L, 2, "alignment");
+ elem->align = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
+ lua_pop(L, 1);
+
+ lua_getfield(L, 2, "offset");
+ elem->offset = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
+ lua_pop(L, 1);
+
+ lua_getfield(L, 2, "world_pos");
+ elem->world_pos = lua_istable(L, -1) ? read_v3f(L, -1) : v3f();
+ lua_pop(L, 1);
+
+ /* check for known deprecated element usage */
+ if ((elem->type == HUD_ELEM_STATBAR) && (elem->size == v2s32()))
+ log_deprecated(L,"Deprecated usage of statbar without size!");
+}
+
+void push_hud_element(lua_State *L, HudElement *elem)
+{
+ lua_newtable(L);
+
+ lua_pushstring(L, es_HudElementType[(u8)elem->type].str);
+ lua_setfield(L, -2, "type");
+
+ push_v2f(L, elem->pos);
+ lua_setfield(L, -2, "position");
+
+ lua_pushstring(L, elem->name.c_str());
+ lua_setfield(L, -2, "name");
+
+ push_v2f(L, elem->scale);
+ lua_setfield(L, -2, "scale");
+
+ lua_pushstring(L, elem->text.c_str());
+ lua_setfield(L, -2, "text");
+
+ lua_pushnumber(L, elem->number);
+ lua_setfield(L, -2, "number");
+
+ lua_pushnumber(L, elem->item);
+ lua_setfield(L, -2, "item");
+
+ lua_pushnumber(L, elem->dir);
+ lua_setfield(L, -2, "direction");
+
+ push_v2f(L, elem->offset);
+ lua_setfield(L, -2, "offset");
+
+ push_v2f(L, elem->align);
+ lua_setfield(L, -2, "alignment");
+
+ push_v2s32(L, elem->size);
+ lua_setfield(L, -2, "size");
+
+ // Deprecated, only for compatibility's sake
+ lua_pushnumber(L, elem->dir);
+ lua_setfield(L, -2, "dir");
+
+ push_v3f(L, elem->world_pos);
+ lua_setfield(L, -2, "world_pos");
+
+ lua_pushnumber(L, elem->z_index);
+ lua_setfield(L, -2, "z_index");
+}
+
+HudElementStat read_hud_change(lua_State *L, HudElement *elem, void **value)
+{
+ HudElementStat stat = HUD_STAT_NUMBER;
+ if (lua_isstring(L, 3)) {
+ int statint;
+ std::string statstr = lua_tostring(L, 3);
+ stat = string_to_enum(es_HudElementStat, statint, statstr) ?
+ (HudElementStat)statint : stat;
+ }
+
+ switch (stat) {
+ case HUD_STAT_POS:
+ elem->pos = read_v2f(L, 4);
+ *value = &elem->pos;
+ break;
+ case HUD_STAT_NAME:
+ elem->name = luaL_checkstring(L, 4);
+ *value = &elem->name;
+ break;
+ case HUD_STAT_SCALE:
+ elem->scale = read_v2f(L, 4);
+ *value = &elem->scale;
+ break;
+ case HUD_STAT_TEXT:
+ elem->text = luaL_checkstring(L, 4);
+ *value = &elem->text;
+ break;
+ case HUD_STAT_NUMBER:
+ elem->number = luaL_checknumber(L, 4);
+ *value = &elem->number;
+ break;
+ case HUD_STAT_ITEM:
+ elem->item = luaL_checknumber(L, 4);
+ *value = &elem->item;
+ break;
+ case HUD_STAT_DIR:
+ elem->dir = luaL_checknumber(L, 4);
+ *value = &elem->dir;
+ break;
+ case HUD_STAT_ALIGN:
+ elem->align = read_v2f(L, 4);
+ *value = &elem->align;
+ break;
+ case HUD_STAT_OFFSET:
+ elem->offset = read_v2f(L, 4);
+ *value = &elem->offset;
+ break;
+ case HUD_STAT_WORLD_POS:
+ elem->world_pos = read_v3f(L, 4);
+ *value = &elem->world_pos;
+ break;
+ case HUD_STAT_SIZE:
+ elem->size = read_v2s32(L, 4);
+ *value = &elem->size;
+ break;
+ case HUD_STAT_Z_INDEX:
+ elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX, luaL_checknumber(L, 4)));
+ *value = &elem->z_index;
+ break;
+ }
+ return stat;
+}
+
+/******************************************************************************/
+
+// Indices must match values in `enum CollisionType` exactly!!
+static const char *collision_type_str[] = {
+ "node",
+ "object",
+};
+
+// Indices must match values in `enum CollisionAxis` exactly!!
+static const char *collision_axis_str[] = {
+ "x",
+ "y",
+ "z",
+};
+
+void push_collision_move_result(lua_State *L, const collisionMoveResult &res)
+{
+ lua_createtable(L, 0, 4);
+
+ setboolfield(L, -1, "touching_ground", res.touching_ground);
+ setboolfield(L, -1, "collides", res.collides);
+ setboolfield(L, -1, "standing_on_object", res.standing_on_object);
+
+ /* collisions */
+ lua_createtable(L, res.collisions.size(), 0);
+ int i = 1;
+ for (const auto &c : res.collisions) {
+ lua_createtable(L, 0, 5);
+
+ lua_pushstring(L, collision_type_str[c.type]);
+ lua_setfield(L, -2, "type");
+
+ assert(c.axis != COLLISION_AXIS_NONE);
+ lua_pushstring(L, collision_axis_str[c.axis]);
+ lua_setfield(L, -2, "axis");
+
+ if (c.type == COLLISION_NODE) {
+ push_v3s16(L, c.node_p);
+ lua_setfield(L, -2, "node_pos");
+ }
+
+ push_v3f(L, c.old_speed / BS);
+ lua_setfield(L, -2, "old_velocity");
+
+ push_v3f(L, c.new_speed / BS);
+ lua_setfield(L, -2, "new_velocity");
+
+ lua_rawseti(L, -2, i++);
+ }
+ lua_setfield(L, -2, "collisions");
+ /**/
+}