From f4d718c53843c5e18243d0851b9c7790b0853334 Mon Sep 17 00:00:00 2001 From: Rogier Date: Wed, 14 Dec 2016 16:23:25 +0100 Subject: Minimal game: Use field 'tiles' instead of 'tile_images' --- games/minimal/mods/experimental/init.lua | 6 +++--- games/minimal/mods/stairs/init.lua | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'games') diff --git a/games/minimal/mods/experimental/init.lua b/games/minimal/mods/experimental/init.lua index 729191bce..142734cda 100644 --- a/games/minimal/mods/experimental/init.lua +++ b/games/minimal/mods/experimental/init.lua @@ -28,7 +28,7 @@ minetest.after(1.0, switch_player_visual) ]] minetest.register_node("experimental:soundblock", { - tile_images = {"unknown_node.png", "default_tnt_bottom.png", + tiles = {"unknown_node.png", "default_tnt_bottom.png", "default_tnt_side.png", "default_tnt_side.png", "default_tnt_side.png", "default_tnt_side.png"}, inventory_image = minetest.inventorycube("unknown_node.png", @@ -120,7 +120,7 @@ minetest.register_craft({ }) minetest.register_node("experimental:tnt", { - tile_images = {"default_tnt_top.png", "default_tnt_bottom.png", + tiles = {"default_tnt_top.png", "default_tnt_bottom.png", "default_tnt_side.png", "default_tnt_side.png", "default_tnt_side.png", "default_tnt_side.png"}, inventory_image = minetest.inventorycube("default_tnt_top.png", @@ -453,7 +453,7 @@ minetest.register_abm({ minetest.register_node("experimental:tester_node_1", { description = "Tester Node 1 (construct/destruct/timer)", - tile_images = {"wieldhand.png"}, + tiles = {"wieldhand.png"}, groups = {oddly_breakable_by_hand=2}, sounds = default.node_sound_wood_defaults(), -- This was known to cause a bug in minetest.item_place_node() when used diff --git a/games/minimal/mods/stairs/init.lua b/games/minimal/mods/stairs/init.lua index 4929d1370..c3bbc561e 100644 --- a/games/minimal/mods/stairs/init.lua +++ b/games/minimal/mods/stairs/init.lua @@ -5,7 +5,7 @@ function stairs.register_stair(subname, recipeitem, groups, images, description) minetest.register_node("stairs:stair_" .. subname, { description = description, drawtype = "nodebox", - tile_images = images, + tiles = images, paramtype = "light", paramtype2 = "facedir", is_ground_content = true, @@ -34,7 +34,7 @@ function stairs.register_slab(subname, recipeitem, groups, images, description) minetest.register_node("stairs:slab_" .. subname, { description = description, drawtype = "nodebox", - tile_images = images, + tiles = images, paramtype = "light", is_ground_content = true, groups = groups, -- cgit v1.2.3 From 7057c196c442ff3484b53f48d940f4c9e0ffe23a Mon Sep 17 00:00:00 2001 From: Luke Puchner-Hardman Date: Tue, 23 Sep 2014 14:39:34 +0200 Subject: Added "[sheet" to the texture special commands. "[sheet:WxH:X,Y" assumes the base image is a tilesheet with W*H tiles on it and crops to the tile at position X,Y. Basically it works like "[verticalframe" but in 2D. For testing, I combined the four default_chest images into one. --- doc/lua_api.txt | 5 +++ games/minimal/mods/default/init.lua | 10 +++-- .../mods/default/textures/default_chest.png | Bin 0 -> 263 bytes .../mods/default/textures/default_chest_front.png | Bin 114 -> 0 bytes .../mods/default/textures/default_chest_lock.png | Bin 145 -> 0 bytes .../mods/default/textures/default_chest_side.png | Bin 98 -> 0 bytes .../mods/default/textures/default_chest_top.png | Bin 93 -> 0 bytes src/client/tile.cpp | 43 +++++++++++++++++++++ 8 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 games/minimal/mods/default/textures/default_chest.png delete mode 100644 games/minimal/mods/default/textures/default_chest_front.png delete mode 100644 games/minimal/mods/default/textures/default_chest_lock.png delete mode 100644 games/minimal/mods/default/textures/default_chest_side.png delete mode 100644 games/minimal/mods/default/textures/default_chest_top.png (limited to 'games') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index d2ddc635b..648a29303 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -403,6 +403,11 @@ Apply a mask to the base image. The mask is applied using binary AND. +#### `[sheet:x:,` +Retrieves a tile at position x,y from the base image +which it assumes to be a tilesheet with dimensions w,h. + + #### `[colorize::` Colorize the textures with the given color. `` is specified as a `ColorString`. diff --git a/games/minimal/mods/default/init.lua b/games/minimal/mods/default/init.lua index bff7860e3..f532e7193 100644 --- a/games/minimal/mods/default/init.lua +++ b/games/minimal/mods/default/init.lua @@ -1130,8 +1130,9 @@ minetest.register_node("default:sign_wall", { minetest.register_node("default:chest", { description = "Chest", - tiles ={"default_chest_top.png", "default_chest_top.png", "default_chest_side.png", - "default_chest_side.png", "default_chest_side.png", "default_chest_front.png"}, + tiles ={"default_chest.png^[sheet:2x2:0,0", "default_chest.png^[sheet:2x2:0,0", + "default_chest.png^[sheet:2x2:1,0", "default_chest.png^[sheet:2x2:1,0", + "default_chest.png^[sheet:2x2:1,0", "default_chest.png^[sheet:2x2:0,1"}, paramtype2 = "facedir", groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2}, legacy_facedir_simple = true, @@ -1164,8 +1165,9 @@ end minetest.register_node("default:chest_locked", { description = "Locked Chest", - tiles ={"default_chest_top.png", "default_chest_top.png", "default_chest_side.png", - "default_chest_side.png", "default_chest_side.png", "default_chest_lock.png"}, + tiles ={"default_chest.png^[sheet:2x2:0,0", "default_chest.png^[sheet:2x2:0,0", + "default_chest.png^[sheet:2x2:1,0", "default_chest.png^[sheet:2x2:1,0", + "default_chest.png^[sheet:2x2:1,0", "default_chest.png^[sheet:2x2:1,1"}, paramtype2 = "facedir", groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2}, legacy_facedir_simple = true, diff --git a/games/minimal/mods/default/textures/default_chest.png b/games/minimal/mods/default/textures/default_chest.png new file mode 100644 index 000000000..9746a3fd9 Binary files /dev/null and b/games/minimal/mods/default/textures/default_chest.png differ diff --git a/games/minimal/mods/default/textures/default_chest_front.png b/games/minimal/mods/default/textures/default_chest_front.png deleted file mode 100644 index 55b076c35..000000000 Binary files a/games/minimal/mods/default/textures/default_chest_front.png and /dev/null differ diff --git a/games/minimal/mods/default/textures/default_chest_lock.png b/games/minimal/mods/default/textures/default_chest_lock.png deleted file mode 100644 index 4b2d1af6c..000000000 Binary files a/games/minimal/mods/default/textures/default_chest_lock.png and /dev/null differ diff --git a/games/minimal/mods/default/textures/default_chest_side.png b/games/minimal/mods/default/textures/default_chest_side.png deleted file mode 100644 index ae4847cb6..000000000 Binary files a/games/minimal/mods/default/textures/default_chest_side.png and /dev/null differ diff --git a/games/minimal/mods/default/textures/default_chest_top.png b/games/minimal/mods/default/textures/default_chest_top.png deleted file mode 100644 index ac41551b0..000000000 Binary files a/games/minimal/mods/default/textures/default_chest_top.png and /dev/null differ diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 7f7535df6..4d2166342 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -1827,6 +1827,49 @@ bool TextureSource::generateImagePart(std::string part_of_name, baseimg->setPixel(x, y, c); } } + /* + [sheet:WxH:X,Y + Retrieves a tile at position X,Y (in tiles) + from the base image it assumes to be a + tilesheet with dimensions W,H (in tiles). + */ + else if (part_of_name.substr(0,7) == "[sheet:") { + if (baseimg == NULL) { + errorstream << "generateImagePart(): baseimg != NULL " + << "for part_of_name=\"" << part_of_name + << "\", cancelling." << std::endl; + return false; + } + + Strfnd sf(part_of_name); + sf.next(":"); + u32 w0 = stoi(sf.next("x")); + u32 h0 = stoi(sf.next(":")); + u32 x0 = stoi(sf.next(",")); + u32 y0 = stoi(sf.next(":")); + + core::dimension2d img_dim = baseimg->getDimension(); + core::dimension2d tile_dim(v2u32(img_dim) / v2u32(w0, h0)); + + video::IImage *img = driver->createImage( + video::ECF_A8R8G8B8, tile_dim); + if (!img) { + errorstream << "generateImagePart(): Could not create image " + << "for part_of_name=\"" << part_of_name + << "\", cancelling." << std::endl; + return false; + } + + img->fill(video::SColor(0,0,0,0)); + v2u32 vdim(tile_dim); + core::rect rect(v2s32(x0 * vdim.X, y0 * vdim.Y), tile_dim); + baseimg->copyToWithAlpha(img, v2s32(0), rect, + video::SColor(255,255,255,255), NULL); + + // Replace baseimg + baseimg->drop(); + baseimg = img; + } else { errorstream << "generateImagePart(): Invalid " -- cgit v1.2.3 From a07b032245bef76a7695e139a9daca7cb646a73d Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 23 Dec 2016 14:43:56 +0100 Subject: Add 2D sheet animation for nodes --- doc/lua_api.txt | 21 ++++++++- games/minimal/mods/default/init.lua | 7 ++- .../textures/default_lava_source_animated.png | Bin 2902 -> 3145 bytes src/nodedef.cpp | 2 +- src/particles.cpp | 2 +- src/script/common/c_content.cpp | 25 +++++++--- src/tileanimation.cpp | 52 +++++++++++++++------ src/tileanimation.h | 6 +++ 8 files changed, 88 insertions(+), 27 deletions(-) (limited to 'games') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 648a29303..6166826af 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -3702,7 +3702,26 @@ Definition tables * `image` (name) ### Tile animation definition -* `{type="vertical_frames", aspect_w=16, aspect_h=16, length=3.0}` + + { + type = "vertical_frames", + aspect_w = 16, + -- ^ specify width of a frame in pixels + aspect_h = 16, + -- ^ specify height of a frame in pixels + length = 3.0, + -- ^ specify full loop length + } + + { + type = "sheet_2d", + frames_w = 5, + -- ^ specify width in number of frames + frames_h = 3, + -- ^ specify height in number of frames + frame_length = 0.5, + -- ^ specify length of a single frame + } ### Node definition (`register_node`) diff --git a/games/minimal/mods/default/init.lua b/games/minimal/mods/default/init.lua index f532e7193..2f73b53ef 100644 --- a/games/minimal/mods/default/init.lua +++ b/games/minimal/mods/default/init.lua @@ -1044,8 +1044,11 @@ minetest.register_node("default:lava_source", { inventory_image = minetest.inventorycube("default_lava.png"), drawtype = "liquid", --tiles ={"default_lava.png"}, - tiles ={ - {name="default_lava_source_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=3.0}} + tiles = { + { + name = "default_lava_source_animated.png", + animation = {type="sheet_2d", frames_w=3, frames_h=2, frame_length=0.5} + } }, special_tiles = { -- New-style lava source material (mostly unused) diff --git a/games/minimal/mods/default/textures/default_lava_source_animated.png b/games/minimal/mods/default/textures/default_lava_source_animated.png index aa9d57cf1..54f4c0ddd 100644 Binary files a/games/minimal/mods/default/textures/default_lava_source_animated.png and b/games/minimal/mods/default/textures/default_lava_source_animated.png differ diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 21bceb94d..92cdf738e 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -528,7 +528,7 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, tile->material_flags = 0; if (backface_culling) tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING; - if (tiledef->animation.type == TAT_VERTICAL_FRAMES) + if (tiledef->animation.type != TAT_NONE) tile->material_flags |= MATERIAL_FLAG_ANIMATION; if (tiledef->tileable_horizontal) tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL; diff --git a/src/particles.cpp b/src/particles.cpp index e9ddba986..97f42e2c4 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -570,7 +570,7 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s video::ITexture *texture; // Only use first frame of animated texture - if(tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION) + if (tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION) texture = tiles[texid].frames[0].texture; else texture = tiles[texid].texture; diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 6cd1d040b..b9bcfef69 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -39,6 +39,7 @@ struct EnumString es_TileAnimationType[] = { {TAT_NONE, "none"}, {TAT_VERTICAL_FRAMES, "vertical_frames"}, + {TAT_SHEET_2D, "sheet_2d"}, {0, NULL}, }; @@ -334,16 +335,26 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype) // animation = {} lua_getfield(L, index, "animation"); if(lua_istable(L, -1)){ - // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0} tiledef.animation.type = (TileAnimationType) getenumfield(L, -1, "type", es_TileAnimationType, TAT_NONE); - tiledef.animation.vertical_frames.aspect_w = - getintfield_default(L, -1, "aspect_w", 16); - tiledef.animation.vertical_frames.aspect_h = - getintfield_default(L, -1, "aspect_h", 16); - tiledef.animation.vertical_frames.length = - getfloatfield_default(L, -1, "length", 1.0); + if (tiledef.animation.type == TAT_VERTICAL_FRAMES) { + // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0} + tiledef.animation.vertical_frames.aspect_w = + getintfield_default(L, -1, "aspect_w", 16); + tiledef.animation.vertical_frames.aspect_h = + getintfield_default(L, -1, "aspect_h", 16); + tiledef.animation.vertical_frames.length = + getfloatfield_default(L, -1, "length", 1.0); + } else if (tiledef.animation.type == TAT_SHEET_2D) { + // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5} + getintfield(L, -1, "frames_w", + tiledef.animation.sheet_2d.frames_w); + getintfield(L, -1, "frames_h", + tiledef.animation.sheet_2d.frames_h); + getfloatfield(L, -1, "frame_length", + tiledef.animation.sheet_2d.frame_length); + } } lua_pop(L, 1); } diff --git a/src/tileanimation.cpp b/src/tileanimation.cpp index 891478c9f..a23eecc2e 100644 --- a/src/tileanimation.cpp +++ b/src/tileanimation.cpp @@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., void TileAnimationParams::serialize(std::ostream &os, u16 protocol_version) const { - if(protocol_version < 29 /* TODO bump */) { + if (protocol_version < 29) { if (type == TAT_VERTICAL_FRAMES) { writeU8(os, type); writeU16(os, vertical_frames.aspect_w); @@ -41,47 +41,69 @@ void TileAnimationParams::serialize(std::ostream &os, u16 protocol_version) cons writeU16(os, vertical_frames.aspect_w); writeU16(os, vertical_frames.aspect_h); writeF1000(os, vertical_frames.length); + } else if (type == TAT_SHEET_2D) { + writeU8(os, sheet_2d.frames_w); + writeU8(os, sheet_2d.frames_h); + writeF1000(os, sheet_2d.frame_length); } } void TileAnimationParams::deSerialize(std::istream &is, u16 protocol_version) { type = (TileAnimationType) readU8(is); - if(protocol_version < 29 /* TODO bump */) { + if (protocol_version < 29) { vertical_frames.aspect_w = readU16(is); vertical_frames.aspect_h = readU16(is); vertical_frames.length = readF1000(is); return; } - if(type == TAT_VERTICAL_FRAMES) { + if (type == TAT_VERTICAL_FRAMES) { vertical_frames.aspect_w = readU16(is); vertical_frames.aspect_h = readU16(is); vertical_frames.length = readF1000(is); + } else if (type == TAT_SHEET_2D) { + sheet_2d.frames_w = readU8(is); + sheet_2d.frames_h = readU8(is); + sheet_2d.frame_length = readF1000(is); } } void TileAnimationParams::determineParams(v2u32 texture_size, int *frame_count, int *frame_length_ms) const { - if (type == TAT_NONE) { + if (type == TAT_VERTICAL_FRAMES) { + int frame_height = (float)texture_size.X / + (float)vertical_frames.aspect_w * + (float)vertical_frames.aspect_h; + int _frame_count = texture_size.Y / frame_height; + if (frame_count) + *frame_count = _frame_count; + if (frame_length_ms) + *frame_length_ms = 1000.0 * vertical_frames.length / _frame_count; + } else if (type == TAT_SHEET_2D) { + if (frame_count) + *frame_count = sheet_2d.frames_w * sheet_2d.frames_h; + if (frame_length_ms) + *frame_length_ms = 1000 * sheet_2d.frame_length; + } else { // TAT_NONE *frame_count = 1; *frame_length_ms = 1000; - return; } - int frame_height = (float)texture_size.X / - (float)vertical_frames.aspect_w * - (float)vertical_frames.aspect_h; - if (frame_count) - *frame_count = texture_size.Y / frame_height; - if (frame_length_ms) - *frame_length_ms = 1000.0 * vertical_frames.length / (texture_size.Y / frame_height); } void TileAnimationParams::getTextureModifer(std::ostream &os, v2u32 texture_size, int frame) const { if (type == TAT_NONE) return; - int frame_count; - determineParams(texture_size, &frame_count, NULL); - os << "^[verticalframe:" << frame_count << ":" << frame; + if (type == TAT_VERTICAL_FRAMES) { + int frame_count; + determineParams(texture_size, &frame_count, NULL); + os << "^[verticalframe:" << frame_count << ":" << frame; + } else if (type == TAT_SHEET_2D) { + int q, r; + q = frame / sheet_2d.frames_w; + r = frame % sheet_2d.frames_w; + os << "^[sheet:" << sheet_2d.frames_w << "x" << sheet_2d.frames_h + << ":" << r << "," << q; + } } diff --git a/src/tileanimation.h b/src/tileanimation.h index d5172ed50..289ce515b 100644 --- a/src/tileanimation.h +++ b/src/tileanimation.h @@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., enum TileAnimationType { TAT_NONE = 0, TAT_VERTICAL_FRAMES = 1, + TAT_SHEET_2D = 2, }; struct TileAnimationParams { @@ -38,6 +39,11 @@ struct TileAnimationParams { int aspect_h; // height for aspect ratio float length; // seconds } vertical_frames; + struct { + int frames_w; // number of frames left-to-right + int frames_h; // number of frames top-to-bottom + float frame_length; // seconds + } sheet_2d; }; void serialize(std::ostream &os, u16 protocol_version) const; -- cgit v1.2.3 From 7279f0b37335396c85f6bdd7dc67ff56e53df0f9 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 14 Jan 2017 16:48:49 +0100 Subject: Add particle animation, glow This is implemented by reusing and extending the TileAnimation code for the methods used by particles. --- doc/lua_api.txt | 7 ++- games/minimal/mods/experimental/init.lua | 37 ++++++++++++++ src/client.h | 5 ++ src/network/clientpackethandler.cpp | 18 +++++++ src/network/networkpacket.cpp | 2 +- src/network/networkpacket.h | 5 +- src/nodedef.cpp | 2 +- src/particles.cpp | 74 ++++++++++++++++++++++----- src/particles.h | 12 ++++- src/script/common/c_content.cpp | 60 +++++++++++++--------- src/script/common/c_content.h | 1 + src/script/lua_api/l_particles.cpp | 27 +++++++++- src/server.cpp | 85 +++++++++++++++++++++++--------- src/server.h | 18 ++++--- src/tileanimation.cpp | 32 ++++++++++-- src/tileanimation.h | 4 +- 16 files changed, 311 insertions(+), 78 deletions(-) (limited to 'games') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index c96131455..9bdc01c07 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -4180,10 +4180,15 @@ The Biome API is still in an experimental phase and subject to change. -- ^ vertical: if true faces player using y axis only texture = "image.png", -- ^ Uses texture (string) - playername = "singleplayer" + playername = "singleplayer", -- ^ optional, if specified spawns particle only on the player's client + animation = {Tile Animation definition}, + -- ^ optional, specifies how to animate the particle texture + glow = 0 + -- ^ optional, specify particle self-luminescence in darkness } + ### `ParticleSpawner` definition (`add_particlespawner`) { diff --git a/games/minimal/mods/experimental/init.lua b/games/minimal/mods/experimental/init.lua index 142734cda..5e98e1a80 100644 --- a/games/minimal/mods/experimental/init.lua +++ b/games/minimal/mods/experimental/init.lua @@ -523,6 +523,43 @@ minetest.register_craft({ } }) +minetest.register_craftitem("experimental:tester_tool_2", { + description = "Tester Tool 2", + inventory_image = "experimental_tester_tool_1.png^[invert:g", + on_use = function(itemstack, user, pointed_thing) + local pos = minetest.get_pointed_thing_position(pointed_thing, true) + if pos == nil then return end + pos = vector.add(pos, {x=0, y=0.5, z=0}) + local tex, anim + if math.random(0, 1) == 0 then + tex = "default_lava_source_animated.png" + anim = {type="sheet_2d", frames_w=3, frames_h=2, frame_length=0.5} + else + tex = "default_lava_flowing_animated.png" + anim = {type="vertical_frames", aspect_w=16, aspect_h=16, length=3.3} + end + + minetest.add_particle({ + pos = pos, + velocity = {x=0, y=0, z=0}, + acceleration = {x=0, y=0.04, z=0}, + expirationtime = 6, + collisiondetection = true, + texture = tex, + animation = anim, + size = 4, + glow = math.random(0, 5), + }) + end, +}) + +minetest.register_craft({ + output = 'experimental:tester_tool_2', + recipe = { + {'group:crumbly','group:crumbly'}, + } +}) + --[[minetest.register_on_joinplayer(function(player) minetest.after(3, function() player:set_inventory_formspec("size[8,7.5]".. diff --git a/src/client.h b/src/client.h index f84246deb..b33358d94 100644 --- a/src/client.h +++ b/src/client.h @@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "hud.h" #include "particles.h" #include "mapnode.h" +#include "tileanimation.h" struct MeshMakeData; class MapBlockMesh; @@ -186,6 +187,8 @@ struct ClientEvent bool collision_removal; bool vertical; std::string *texture; + struct TileAnimationParams animation; + u8 glow; } spawn_particle; struct{ u16 amount; @@ -206,6 +209,8 @@ struct ClientEvent bool vertical; std::string *texture; u32 id; + struct TileAnimationParams animation; + u8 glow; } add_particlespawner; struct{ u32 id; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 411982f69..b11f73e86 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "network/clientopcodes.h" #include "util/serialize.h" #include "util/srp.h" +#include "tileanimation.h" void Client::handleCommand_Deprecated(NetworkPacket* pkt) { @@ -896,9 +897,14 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt) std::string texture = deSerializeLongString(is); bool vertical = false; bool collision_removal = false; + struct TileAnimationParams animation; + animation.type = TAT_NONE; + u8 glow = 0; try { vertical = readU8(is); collision_removal = readU8(is); + animation.deSerialize(is, m_proto_ver); + glow = readU8(is); } catch (...) {} ClientEvent event; @@ -912,6 +918,8 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt) event.spawn_particle.collision_removal = collision_removal; event.spawn_particle.vertical = vertical; event.spawn_particle.texture = new std::string(texture); + event.spawn_particle.animation = animation; + event.spawn_particle.glow = glow; m_client_event_queue.push(event); } @@ -943,12 +951,20 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) bool vertical = false; bool collision_removal = false; + struct TileAnimationParams animation; + animation.type = TAT_NONE; + u8 glow = 0; u16 attached_id = 0; try { *pkt >> vertical; *pkt >> collision_removal; *pkt >> attached_id; + // This is horrible but required (why are there two ways to deserialize pkts?) + std::string datastring(pkt->getRemainingString(), pkt->getRemainingBytes()); + std::istringstream is(datastring, std::ios_base::binary); + animation.deSerialize(is, m_proto_ver); + glow = readU8(is); } catch (...) {} ClientEvent event; @@ -971,6 +987,8 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) event.add_particlespawner.vertical = vertical; event.add_particlespawner.texture = new std::string(texture); event.add_particlespawner.id = id; + event.add_particlespawner.animation = animation; + event.add_particlespawner.glow = glow; m_client_event_queue.push(event); } diff --git a/src/network/networkpacket.cpp b/src/network/networkpacket.cpp index 388afc18e..91e6c58e2 100644 --- a/src/network/networkpacket.cpp +++ b/src/network/networkpacket.cpp @@ -63,7 +63,7 @@ void NetworkPacket::putRawPacket(u8 *data, u32 datasize, u16 peer_id) m_data = std::vector(&data[2], &data[2 + m_datasize]); } -char* NetworkPacket::getString(u32 from_offset) +const char* NetworkPacket::getString(u32 from_offset) { checkReadOffset(from_offset, 0); diff --git a/src/network/networkpacket.h b/src/network/networkpacket.h index 524470999..3e436aba9 100644 --- a/src/network/networkpacket.h +++ b/src/network/networkpacket.h @@ -41,12 +41,15 @@ public: u16 getPeerId() { return m_peer_id; } u16 getCommand() { return m_command; } const u32 getRemainingBytes() const { return m_datasize - m_read_offset; } + const char* getRemainingString() { return getString(m_read_offset); } // Returns a c-string without copying. // A better name for this would be getRawString() - char* getString(u32 from_offset); + const char* getString(u32 from_offset); // major difference to putCString(): doesn't write len into the buffer void putRawString(const char* src, u32 len); + void putRawString(const std::string &src) + { putRawString(src.c_str(), src.size()); } NetworkPacket& operator>>(std::string& dst); NetworkPacket& operator<<(std::string src); diff --git a/src/nodedef.cpp b/src/nodedef.cpp index b7d023897..a4af26e87 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -541,7 +541,7 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, if (tile->material_flags & MATERIAL_FLAG_ANIMATION) { int frame_length_ms; tiledef->animation.determineParams(tile->texture->getOriginalSize(), - &frame_count, &frame_length_ms); + &frame_count, &frame_length_ms, NULL); tile->animation_frame_count = frame_count; tile->animation_frame_length_ms = frame_length_ms; } diff --git a/src/particles.cpp b/src/particles.cpp index d9eb3cfa5..5f17763e0 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -54,7 +54,9 @@ Particle::Particle( bool vertical, video::ITexture *texture, v2f texpos, - v2f texsize + v2f texsize, + const struct TileAnimationParams &anim, + u8 glow ): scene::ISceneNode(smgr->getRootSceneNode(), smgr) { @@ -71,7 +73,9 @@ Particle::Particle( m_material.setTexture(0, texture); m_texpos = texpos; m_texsize = texsize; - + m_animation = anim; + m_animation_frame = 0; + m_animation_time = 0.0; // Particle related m_pos = pos; @@ -84,6 +88,7 @@ Particle::Particle( m_collisiondetection = collisiondetection; m_collision_removal = collision_removal; m_vertical = vertical; + m_glow = glow; // Irrlicht stuff m_collisionbox = aabb3f @@ -142,6 +147,18 @@ void Particle::step(float dtime) m_velocity += m_acceleration * dtime; m_pos += m_velocity * dtime; } + if (m_animation.type != TAT_NONE) { + m_animation_time += dtime; + int frame_length_i, frame_count; + m_animation.determineParams( + m_material.getTexture(0)->getSize(), + &frame_count, &frame_length_i, NULL); + float frame_length = frame_length_i / 1000.0; + while (m_animation_time > frame_length) { + m_animation_frame++; + m_animation_time -= frame_length; + } + } // Update lighting updateLight(); @@ -166,16 +183,32 @@ void Particle::updateLight() else light = blend_light(m_env->getDayNightRatio(), LIGHT_SUN, 0); - m_light = decode_light(light); + m_light = decode_light(light + m_glow); } void Particle::updateVertices() { video::SColor c(255, m_light, m_light, m_light); - f32 tx0 = m_texpos.X; - f32 tx1 = m_texpos.X + m_texsize.X; - f32 ty0 = m_texpos.Y; - f32 ty1 = m_texpos.Y + m_texsize.Y; + f32 tx0, tx1, ty0, ty1; + + if (m_animation.type != TAT_NONE) { + const v2u32 texsize = m_material.getTexture(0)->getSize(); + v2f texcoord, framesize_f; + v2u32 framesize; + texcoord = m_animation.getTextureCoords(texsize, m_animation_frame); + m_animation.determineParams(texsize, NULL, NULL, &framesize); + framesize_f = v2f(framesize.X / (float) texsize.X, framesize.Y / (float) texsize.Y); + + tx0 = m_texpos.X + texcoord.X; + tx1 = m_texpos.X + texcoord.X + framesize_f.X * m_texsize.X; + ty0 = m_texpos.Y + texcoord.Y; + ty1 = m_texpos.Y + texcoord.Y + framesize_f.Y * m_texsize.Y; + } else { + tx0 = m_texpos.X; + tx1 = m_texpos.X + m_texsize.X; + ty0 = m_texpos.Y; + ty1 = m_texpos.Y + m_texsize.Y; + } m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0, c, tx0, ty1); @@ -210,7 +243,9 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr, v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime, float minsize, float maxsize, bool collisiondetection, bool collision_removal, u16 attached_id, bool vertical, - video::ITexture *texture, u32 id, ParticleManager *p_manager) : + video::ITexture *texture, u32 id, const struct TileAnimationParams &anim, + u8 glow, + ParticleManager *p_manager) : m_particlemanager(p_manager) { m_gamedef = gamedef; @@ -234,6 +269,8 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr, m_vertical = vertical; m_texture = texture; m_time = 0; + m_animation = anim; + m_glow = glow; for (u16 i = 0; i<=m_amount; i++) { @@ -309,7 +346,9 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env) m_vertical, m_texture, v2f(0.0, 0.0), - v2f(1.0, 1.0)); + v2f(1.0, 1.0), + m_animation, + m_glow); m_particlemanager->addParticle(toadd); } i = m_spawntimes.erase(i); @@ -363,7 +402,9 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env) m_vertical, m_texture, v2f(0.0, 0.0), - v2f(1.0, 1.0)); + v2f(1.0, 1.0), + m_animation, + m_glow); m_particlemanager->addParticle(toadd); } } @@ -494,6 +535,8 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client, event->add_particlespawner.vertical, texture, event->add_particlespawner.id, + event->add_particlespawner.animation, + event->add_particlespawner.glow, this); /* delete allocated content of event */ @@ -529,13 +572,16 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client, event->spawn_particle.vertical, texture, v2f(0.0, 0.0), - v2f(1.0, 1.0)); + v2f(1.0, 1.0), + event->spawn_particle.animation, + event->spawn_particle.glow); addParticle(toadd); delete event->spawn_particle.pos; delete event->spawn_particle.vel; delete event->spawn_particle.acc; + delete event->spawn_particle.texture; break; } @@ -564,6 +610,8 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s // Texture u8 texid = myrand_range(0, 5); video::ITexture *texture; + struct TileAnimationParams anim; + anim.type = TAT_NONE; // Only use first frame of animated texture if (tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION) @@ -605,7 +653,9 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s false, texture, texpos, - texsize); + texsize, + anim, + 0); addParticle(toadd); } diff --git a/src/particles.h b/src/particles.h index 00cb2c08e..5464e6672 100644 --- a/src/particles.h +++ b/src/particles.h @@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/tile.h" #include "localplayer.h" #include "environment.h" +#include "tileanimation.h" struct ClientEvent; class ParticleManager; @@ -50,7 +51,9 @@ class Particle : public scene::ISceneNode bool vertical, video::ITexture *texture, v2f texpos, - v2f texsize + v2f texsize, + const struct TileAnimationParams &anim, + u8 glow ); ~Particle(); @@ -102,6 +105,10 @@ private: bool m_collision_removal; bool m_vertical; v3s16 m_camera_offset; + struct TileAnimationParams m_animation; + float m_animation_time; + int m_animation_frame; + u8 m_glow; }; class ParticleSpawner @@ -123,6 +130,7 @@ class ParticleSpawner bool vertical, video::ITexture *texture, u32 id, + const struct TileAnimationParams &anim, u8 glow, ParticleManager* p_manager); ~ParticleSpawner(); @@ -156,6 +164,8 @@ class ParticleSpawner bool m_collision_removal; bool m_vertical; u16 m_attached_id; + struct TileAnimationParams m_animation; + u8 m_glow; }; /** diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index b9bcfef69..84af4583b 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -322,7 +322,7 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype) } else if(lua_istable(L, index)) { - // {name="default_lava.png", animation={}} + // name="default_lava.png" tiledef.name = ""; getstringfield(L, index, "name", tiledef.name); getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat. @@ -334,28 +334,7 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype) L, index, "tileable_vertical", default_tiling); // animation = {} lua_getfield(L, index, "animation"); - if(lua_istable(L, -1)){ - tiledef.animation.type = (TileAnimationType) - getenumfield(L, -1, "type", es_TileAnimationType, - TAT_NONE); - if (tiledef.animation.type == TAT_VERTICAL_FRAMES) { - // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0} - tiledef.animation.vertical_frames.aspect_w = - getintfield_default(L, -1, "aspect_w", 16); - tiledef.animation.vertical_frames.aspect_h = - getintfield_default(L, -1, "aspect_h", 16); - tiledef.animation.vertical_frames.length = - getfloatfield_default(L, -1, "length", 1.0); - } else if (tiledef.animation.type == TAT_SHEET_2D) { - // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5} - getintfield(L, -1, "frames_w", - tiledef.animation.sheet_2d.frames_w); - getintfield(L, -1, "frames_h", - tiledef.animation.sheet_2d.frames_h); - getfloatfield(L, -1, "frame_length", - tiledef.animation.sheet_2d.frame_length); - } - } + tiledef.animation = read_animation_definition(L, -1); lua_pop(L, 1); } @@ -925,6 +904,41 @@ void read_inventory_list(lua_State *L, int tableindex, } } +/******************************************************************************/ +struct TileAnimationParams read_animation_definition(lua_State *L, int index) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + + struct TileAnimationParams anim; + anim.type = TAT_NONE; + if (!lua_istable(L, index)) + return anim; + + anim.type = (TileAnimationType) + getenumfield(L, index, "type", es_TileAnimationType, + TAT_NONE); + if (anim.type == TAT_VERTICAL_FRAMES) { + // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0} + anim.vertical_frames.aspect_w = + getintfield_default(L, index, "aspect_w", 16); + anim.vertical_frames.aspect_h = + getintfield_default(L, index, "aspect_h", 16); + anim.vertical_frames.length = + getfloatfield_default(L, index, "length", 1.0); + } else if (anim.type == TAT_SHEET_2D) { + // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5} + getintfield(L, index, "frames_w", + anim.sheet_2d.frames_w); + getintfield(L, index, "frames_h", + anim.sheet_2d.frames_h); + getfloatfield(L, index, "frame_length", + anim.sheet_2d.frame_length); + } + + return anim; +} + /******************************************************************************/ ToolCapabilities read_tool_capabilities( lua_State *L, int table) diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h index 2a2228b6d..9641f5c9e 100644 --- a/src/script/common/c_content.h +++ b/src/script/common/c_content.h @@ -79,6 +79,7 @@ void push_hit_params (lua_State *L, ItemStack read_item (lua_State *L, int index, Server *srv); +struct TileAnimationParams read_animation_definition(lua_State *L, int index); ToolCapabilities read_tool_capabilities (lua_State *L, int table); void push_tool_capabilities (lua_State *L, diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp index 667ac7272..7f415844a 100644 --- a/src/script/lua_api/l_particles.cpp +++ b/src/script/lua_api/l_particles.cpp @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_object.h" #include "lua_api/l_internal.h" #include "common/c_converter.h" +#include "common/c_content.h" #include "server.h" #include "particles.h" @@ -34,6 +35,8 @@ with this program; if not, write to the Free Software Foundation, Inc., // collision_removal = bool // vertical = bool // texture = e.g."default_wood.png" +// animation = TileAnimation definition +// glow = num int ModApiParticles::l_add_particle(lua_State *L) { MAP_LOCK_REQUIRED; @@ -47,10 +50,13 @@ int ModApiParticles::l_add_particle(lua_State *L) bool collisiondetection, vertical, collision_removal; collisiondetection = vertical = collision_removal = false; + struct TileAnimationParams animation; std::string texture = ""; std::string playername = ""; + u8 glow = 0; + if (lua_gettop(L) > 1) // deprecated { log_deprecated(L, "Deprecated add_particle call with individual parameters instead of definition"); @@ -101,11 +107,18 @@ int ModApiParticles::l_add_particle(lua_State *L) collision_removal = getboolfield_default(L, 1, "collision_removal", collision_removal); vertical = getboolfield_default(L, 1, "vertical", vertical); + + lua_getfield(L, 1, "animation"); + animation = read_animation_definition(L, -1); + lua_pop(L, 1); + texture = getstringfield_default(L, 1, "texture", ""); playername = getstringfield_default(L, 1, "playername", ""); + + glow = getintfield_default(L, 1, "glow", 0); } getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size, - collisiondetection, collision_removal, vertical, texture); + collisiondetection, collision_removal, vertical, texture, animation, glow); return 1; } @@ -127,6 +140,8 @@ int ModApiParticles::l_add_particle(lua_State *L) // collision_removal = bool // vertical = bool // texture = e.g."default_wood.png" +// animation = TileAnimation definition +// glow = num int ModApiParticles::l_add_particlespawner(lua_State *L) { MAP_LOCK_REQUIRED; @@ -139,9 +154,11 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) time= minexptime= maxexptime= minsize= maxsize= 1; bool collisiondetection, vertical, collision_removal; collisiondetection = vertical = collision_removal = false; + struct TileAnimationParams animation; ServerActiveObject *attached = NULL; std::string texture = ""; std::string playername = ""; + u8 glow = 0; if (lua_gettop(L) > 1) //deprecated { @@ -201,6 +218,10 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) collision_removal = getboolfield_default(L, 1, "collision_removal", collision_removal); + lua_getfield(L, 1, "animation"); + animation = read_animation_definition(L, -1); + lua_pop(L, 1); + lua_getfield(L, 1, "attached"); if (!lua_isnil(L, -1)) { ObjectRef *ref = ObjectRef::checkobject(L, -1); @@ -211,6 +232,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) vertical = getboolfield_default(L, 1, "vertical", vertical); texture = getstringfield_default(L, 1, "texture", ""); playername = getstringfield_default(L, 1, "playername", ""); + glow = getintfield_default(L, 1, "glow", 0); } u32 id = getServer(L)->addParticleSpawner(amount, time, @@ -223,7 +245,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) collision_removal, attached, vertical, - texture, playername); + texture, playername, + animation, glow); lua_pushnumber(L, id); return 1; diff --git a/src/server.cpp b/src/server.cpp index 74d9541c9..d3d5fd3d1 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1662,12 +1662,28 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec, } // Spawns a particle on peer with peer_id -void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration, +void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version, + v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, bool collision_removal, - bool vertical, const std::string &texture) + bool vertical, const std::string &texture, + const struct TileAnimationParams &animation, u8 glow) { DSTACK(FUNCTION_NAME); + if (peer_id == PEER_ID_INEXISTENT) { + // This sucks and should be replaced by a better solution in a refactor: + std::vector clients = m_clients.getClientIDs(); + for (std::vector::iterator i = clients.begin(); i != clients.end(); ++i) { + RemotePlayer *player = m_env->getPlayer(*i); + if (!player) + continue; + SendSpawnParticle(*i, player->protocol_version, + pos, velocity, acceleration, + expirationtime, size, collisiondetection, + collision_removal, vertical, texture, animation, glow); + } + return; + } NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id); @@ -1676,22 +1692,39 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat pkt.putLongString(texture); pkt << vertical; pkt << collision_removal; + // This is horrible but required (why are there two ways to serialize pkts?) + std::ostringstream os(std::ios_base::binary); + animation.serialize(os, protocol_version); + pkt.putRawString(os.str()); + pkt << glow; - if (peer_id != PEER_ID_INEXISTENT) { - Send(&pkt); - } - else { - m_clients.sendToAll(0, &pkt, true); - } + Send(&pkt); } // Adds a ParticleSpawner on peer with peer_id -void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos, +void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version, + u16 amount, float spawntime, v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime, float minsize, float maxsize, bool collisiondetection, bool collision_removal, - u16 attached_id, bool vertical, const std::string &texture, u32 id) + u16 attached_id, bool vertical, const std::string &texture, u32 id, + const struct TileAnimationParams &animation, u8 glow) { DSTACK(FUNCTION_NAME); + if (peer_id == PEER_ID_INEXISTENT) { + // This sucks and should be replaced: + std::vector clients = m_clients.getClientIDs(); + for (std::vector::iterator i = clients.begin(); i != clients.end(); ++i) { + RemotePlayer *player = m_env->getPlayer(*i); + if (!player) + continue; + SendAddParticleSpawner(*i, player->protocol_version, + amount, spawntime, minpos, maxpos, + minvel, maxvel, minacc, maxacc, minexptime, maxexptime, + minsize, maxsize, collisiondetection, collision_removal, + attached_id, vertical, texture, id, animation, glow); + } + return; + } NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id); @@ -1704,13 +1737,13 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3 pkt << id << vertical; pkt << collision_removal; pkt << attached_id; + // This is horrible but required + std::ostringstream os(std::ios_base::binary); + animation.serialize(os, protocol_version); + pkt.putRawString(os.str()); + pkt << glow; - if (peer_id != PEER_ID_INEXISTENT) { - Send(&pkt); - } - else { - m_clients.sendToAll(0, &pkt, true); - } + Send(&pkt); } void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id) @@ -3165,23 +3198,25 @@ void Server::spawnParticle(const std::string &playername, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, bool collision_removal, - bool vertical, const std::string &texture) + bool vertical, const std::string &texture, + const struct TileAnimationParams &animation, u8 glow) { // m_env will be NULL if the server is initializing if (!m_env) return; - u16 peer_id = PEER_ID_INEXISTENT; + u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0; if (playername != "") { RemotePlayer *player = m_env->getPlayer(playername.c_str()); if (!player) return; peer_id = player->peer_id; + proto_ver = player->protocol_version; } - SendSpawnParticle(peer_id, pos, velocity, acceleration, + SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration, expirationtime, size, collisiondetection, - collision_removal, vertical, texture); + collision_removal, vertical, texture, animation, glow); } u32 Server::addParticleSpawner(u16 amount, float spawntime, @@ -3189,18 +3224,20 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime, float minexptime, float maxexptime, float minsize, float maxsize, bool collisiondetection, bool collision_removal, ServerActiveObject *attached, bool vertical, const std::string &texture, - const std::string &playername) + const std::string &playername, const struct TileAnimationParams &animation, + u8 glow) { // m_env will be NULL if the server is initializing if (!m_env) return -1; - u16 peer_id = PEER_ID_INEXISTENT; + u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0; if (playername != "") { RemotePlayer *player = m_env->getPlayer(playername.c_str()); if (!player) return -1; peer_id = player->peer_id; + proto_ver = player->protocol_version; } u16 attached_id = attached ? attached->getId() : 0; @@ -3211,11 +3248,11 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime, else id = m_env->addParticleSpawner(spawntime, attached_id); - SendAddParticleSpawner(peer_id, amount, spawntime, + SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime, minpos, maxpos, minvel, maxvel, minacc, maxacc, minexptime, maxexptime, minsize, maxsize, collisiondetection, collision_removal, attached_id, vertical, - texture, id); + texture, id, animation, glow); return id; } diff --git a/src/server.h b/src/server.h index a86f75f1d..e5121bdc3 100644 --- a/src/server.h +++ b/src/server.h @@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mods.h" #include "inventorymanager.h" #include "subgame.h" +#include "tileanimation.h" // struct TileAnimationParams #include "util/numeric.h" #include "util/thread.h" #include "util/basic_macros.h" @@ -252,7 +253,8 @@ public: v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, bool collision_removal, - bool vertical, const std::string &texture); + bool vertical, const std::string &texture, + const struct TileAnimationParams &animation, u8 glow); u32 addParticleSpawner(u16 amount, float spawntime, v3f minpos, v3f maxpos, @@ -263,7 +265,8 @@ public: bool collisiondetection, bool collision_removal, ServerActiveObject *attached, bool vertical, const std::string &texture, - const std::string &playername); + const std::string &playername, const struct TileAnimationParams &animation, + u8 glow); void deleteParticleSpawner(const std::string &playername, u32 id); @@ -428,7 +431,8 @@ private: void sendDetachedInventories(u16 peer_id); // Adds a ParticleSpawner on peer with peer_id (PEER_ID_INEXISTENT == all) - void SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, + void SendAddParticleSpawner(u16 peer_id, u16 protocol_version, + u16 amount, float spawntime, v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, @@ -436,16 +440,18 @@ private: float minsize, float maxsize, bool collisiondetection, bool collision_removal, u16 attached_id, - bool vertical, const std::string &texture, u32 id); + bool vertical, const std::string &texture, u32 id, + const struct TileAnimationParams &animation, u8 glow); void SendDeleteParticleSpawner(u16 peer_id, u32 id); // Spawns particle on peer with peer_id (PEER_ID_INEXISTENT == all) - void SendSpawnParticle(u16 peer_id, + void SendSpawnParticle(u16 peer_id, u16 protocol_version, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, bool collision_removal, - bool vertical, const std::string &texture); + bool vertical, const std::string &texture, + const struct TileAnimationParams &animation, u8 glow); u32 SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas); void SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable = true); diff --git a/src/tileanimation.cpp b/src/tileanimation.cpp index a23eecc2e..67d27d396 100644 --- a/src/tileanimation.cpp +++ b/src/tileanimation.cpp @@ -69,7 +69,8 @@ void TileAnimationParams::deSerialize(std::istream &is, u16 protocol_version) } } -void TileAnimationParams::determineParams(v2u32 texture_size, int *frame_count, int *frame_length_ms) const +void TileAnimationParams::determineParams(v2u32 texture_size, int *frame_count, + int *frame_length_ms, v2u32 *frame_size) const { if (type == TAT_VERTICAL_FRAMES) { int frame_height = (float)texture_size.X / @@ -80,15 +81,17 @@ void TileAnimationParams::determineParams(v2u32 texture_size, int *frame_count, *frame_count = _frame_count; if (frame_length_ms) *frame_length_ms = 1000.0 * vertical_frames.length / _frame_count; + if (frame_size) + *frame_size = v2u32(texture_size.X, frame_height); } else if (type == TAT_SHEET_2D) { if (frame_count) *frame_count = sheet_2d.frames_w * sheet_2d.frames_h; if (frame_length_ms) *frame_length_ms = 1000 * sheet_2d.frame_length; - } else { // TAT_NONE - *frame_count = 1; - *frame_length_ms = 1000; + if (frame_size) + *frame_size = v2u32(texture_size.X / sheet_2d.frames_w, texture_size.Y / sheet_2d.frames_h); } + // caller should check for TAT_NONE } void TileAnimationParams::getTextureModifer(std::ostream &os, v2u32 texture_size, int frame) const @@ -97,7 +100,7 @@ void TileAnimationParams::getTextureModifer(std::ostream &os, v2u32 texture_size return; if (type == TAT_VERTICAL_FRAMES) { int frame_count; - determineParams(texture_size, &frame_count, NULL); + determineParams(texture_size, &frame_count, NULL, NULL); os << "^[verticalframe:" << frame_count << ":" << frame; } else if (type == TAT_SHEET_2D) { int q, r; @@ -107,3 +110,22 @@ void TileAnimationParams::getTextureModifer(std::ostream &os, v2u32 texture_size << ":" << r << "," << q; } } + +v2f TileAnimationParams::getTextureCoords(v2u32 texture_size, int frame) const +{ + v2u32 ret(0, 0); + if (type == TAT_VERTICAL_FRAMES) { + int frame_height = (float)texture_size.X / + (float)vertical_frames.aspect_w * + (float)vertical_frames.aspect_h; + ret = v2u32(0, frame_height * frame); + } else if (type == TAT_SHEET_2D) { + v2u32 frame_size; + determineParams(texture_size, NULL, NULL, &frame_size); + int q, r; + q = frame / sheet_2d.frames_w; + r = frame % sheet_2d.frames_w; + ret = v2u32(r * frame_size.X, q * frame_size.Y); + } + return v2f(ret.X / (float) texture_size.X, ret.Y / (float) texture_size.Y); +} diff --git a/src/tileanimation.h b/src/tileanimation.h index 289ce515b..eecd3eb96 100644 --- a/src/tileanimation.h +++ b/src/tileanimation.h @@ -48,8 +48,10 @@ struct TileAnimationParams { void serialize(std::ostream &os, u16 protocol_version) const; void deSerialize(std::istream &is, u16 protocol_version); - void determineParams(v2u32 texture_size, int *frame_count, int *frame_length_ms) const; + void determineParams(v2u32 texture_size, int *frame_count, + int *frame_length_ms, v2u32 *frame_size) const; void getTextureModifer(std::ostream &os, v2u32 texture_size, int frame) const; + v2f getTextureCoords(v2u32 texture_size, int frame) const; }; #endif -- cgit v1.2.3 From 5db41d4d213333fc39845e7b752d7976a24da6af Mon Sep 17 00:00:00 2001 From: red-001 Date: Sat, 18 Feb 2017 14:36:29 +0000 Subject: Fix not being able to damage players in minimal (#5266) --- games/minimal/mods/default/init.lua | 61 ++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 14 deletions(-) (limited to 'games') diff --git a/games/minimal/mods/default/init.lua b/games/minimal/mods/default/init.lua index 2f73b53ef..d36e225a3 100644 --- a/games/minimal/mods/default/init.lua +++ b/games/minimal/mods/default/init.lua @@ -39,10 +39,15 @@ minetest.register_item(":", { crumbly = {times={[2]=3.00, [3]=0.70}, uses=0, maxlevel=1}, snappy = {times={[3]=0.40}, uses=0, maxlevel=1}, oddly_breakable_by_hand = {times={[1]=7.00,[2]=4.00,[3]=1.40}, uses=0, maxlevel=3}, - } + }, + damage_groups = {fleshy=1}, } }) +-- +-- Picks +-- + minetest.register_tool("default:pick_wood", { description = "Wooden Pickaxe", inventory_image = "default_tool_woodpick.png", @@ -50,7 +55,8 @@ minetest.register_tool("default:pick_wood", { max_drop_level=0, groupcaps={ cracky={times={[2]=2.00, [3]=1.20}, uses=10, maxlevel=1} - } + }, + damage_groups = {fleshy=2}, }, }) minetest.register_tool("default:pick_stone", { @@ -60,7 +66,8 @@ minetest.register_tool("default:pick_stone", { max_drop_level=0, groupcaps={ cracky={times={[1]=2.00, [2]=1.20, [3]=0.80}, uses=20, maxlevel=1} - } + }, + damage_groups = {fleshy=3}, }, }) minetest.register_tool("default:pick_steel", { @@ -70,7 +77,8 @@ minetest.register_tool("default:pick_steel", { max_drop_level=1, groupcaps={ cracky={times={[1]=4.00, [2]=1.60, [3]=1.00}, uses=10, maxlevel=2} - } + }, + damage_groups = {fleshy=4}, }, }) minetest.register_tool("default:pick_mese", { @@ -83,9 +91,15 @@ minetest.register_tool("default:pick_mese", { cracky={times={[1]=2.0, [2]=1.0, [3]=0.5}, uses=20, maxlevel=3}, crumbly={times={[1]=2.0, [2]=1.0, [3]=0.5}, uses=20, maxlevel=3}, snappy={times={[1]=2.0, [2]=1.0, [3]=0.5}, uses=20, maxlevel=3} - } + }, + damage_groups = {fleshy=4}, }, }) + +-- +-- Shovels +-- + minetest.register_tool("default:shovel_wood", { description = "Wooden Shovel", inventory_image = "default_tool_woodshovel.png", @@ -93,7 +107,8 @@ minetest.register_tool("default:shovel_wood", { max_drop_level=0, groupcaps={ crumbly={times={[1]=2.00, [2]=0.80, [3]=0.50}, uses=10, maxlevel=1} - } + }, + damage_groups = {fleshy=2}, }, }) minetest.register_tool("default:shovel_stone", { @@ -103,7 +118,8 @@ minetest.register_tool("default:shovel_stone", { max_drop_level=0, groupcaps={ crumbly={times={[1]=1.20, [2]=0.50, [3]=0.30}, uses=20, maxlevel=1} - } + }, + damage_groups = {fleshy=3}, }, }) minetest.register_tool("default:shovel_steel", { @@ -113,9 +129,15 @@ minetest.register_tool("default:shovel_steel", { max_drop_level=1, groupcaps={ crumbly={times={[1]=1.00, [2]=0.70, [3]=0.60}, uses=10, maxlevel=2} - } + }, + damage_groups = {fleshy=4}, }, }) + +-- +-- Axes +-- + minetest.register_tool("default:axe_wood", { description = "Wooden Axe", inventory_image = "default_tool_woodaxe.png", @@ -124,7 +146,8 @@ minetest.register_tool("default:axe_wood", { groupcaps={ choppy={times={[2]=1.40, [3]=0.80}, uses=10, maxlevel=1}, fleshy={times={[2]=1.50, [3]=0.80}, uses=10, maxlevel=1} - } + }, + damage_groups = {fleshy=2}, }, }) minetest.register_tool("default:axe_stone", { @@ -135,7 +158,8 @@ minetest.register_tool("default:axe_stone", { groupcaps={ choppy={times={[1]=1.50, [2]=1.00, [3]=0.60}, uses=20, maxlevel=1}, fleshy={times={[2]=1.30, [3]=0.70}, uses=20, maxlevel=1} - } + }, + damage_groups = {fleshy=3}, }, }) minetest.register_tool("default:axe_steel", { @@ -146,9 +170,15 @@ minetest.register_tool("default:axe_steel", { groupcaps={ choppy={times={[1]=2.00, [2]=1.60, [3]=1.00}, uses=10, maxlevel=2}, fleshy={times={[2]=1.10, [3]=0.60}, uses=40, maxlevel=1} - } + }, + damage_groups = {fleshy=3}, }, }) + +-- +-- Swords +-- + minetest.register_tool("default:sword_wood", { description = "Wooden Sword", inventory_image = "default_tool_woodsword.png", @@ -159,7 +189,8 @@ minetest.register_tool("default:sword_wood", { fleshy={times={[2]=1.10, [3]=0.60}, uses=10, maxlevel=1}, snappy={times={[2]=1.00, [3]=0.50}, uses=10, maxlevel=1}, choppy={times={[3]=1.00}, uses=20, maxlevel=0} - } + }, + damage_groups = {fleshy=2}, } }) minetest.register_tool("default:sword_stone", { @@ -172,7 +203,8 @@ minetest.register_tool("default:sword_stone", { fleshy={times={[2]=0.80, [3]=0.40}, uses=20, maxlevel=1}, snappy={times={[2]=0.80, [3]=0.40}, uses=20, maxlevel=1}, choppy={times={[3]=0.90}, uses=20, maxlevel=0} - } + }, + damage_groups = {fleshy=4}, } }) minetest.register_tool("default:sword_steel", { @@ -185,7 +217,8 @@ minetest.register_tool("default:sword_steel", { fleshy={times={[1]=2.00, [2]=0.80, [3]=0.40}, uses=10, maxlevel=2}, snappy={times={[2]=0.70, [3]=0.30}, uses=40, maxlevel=1}, choppy={times={[3]=0.70}, uses=40, maxlevel=0} - } + }, + damage_groups = {fleshy=6}, } }) -- cgit v1.2.3 From 113c85a66a5b23c8c47f1bdb435dd4b27884ed54 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Sat, 22 Apr 2017 00:34:00 +0200 Subject: lua: remove core.cause_error call (#5637) it was used in minimal to trigger core crash, not very useful --- games/minimal/mods/errorhandler_test/init.lua | 106 -------------------------- src/script/lua_api/l_server.cpp | 33 -------- src/script/lua_api/l_server.h | 5 -- 3 files changed, 144 deletions(-) delete mode 100644 games/minimal/mods/errorhandler_test/init.lua (limited to 'games') diff --git a/games/minimal/mods/errorhandler_test/init.lua b/games/minimal/mods/errorhandler_test/init.lua deleted file mode 100644 index 9d1535c1d..000000000 --- a/games/minimal/mods/errorhandler_test/init.lua +++ /dev/null @@ -1,106 +0,0 @@ --- --- exception handler test module --- --- --- To avoid this from crashing the module will startup in inactive mode. --- to make specific errors happen you need to cause them by following --- chat command: --- --- exceptiontest --- --- location has to be one of: --- * mapgen: cause in next on_generate call --- * entity_step: spawn a entity and make it do error in on_step --- * globalstep: do error in next globalstep --- * immediate: cause right in chat handler --- --- errortypes defined are: --- * segv: make sigsegv happen --- * zerodivision: cause a division by zero to happen --- * exception: throw an exception - -if core.cause_error == nil or - type(core.cause_error) ~= "function" then - return -end - - -core.log("action", "WARNING: loading exception handler test module!") - -local exceptiondata = { - tocause = "none", - mapgen = false, - entity_step = false, - globalstep = false, -} - -local exception_entity = -{ - on_step = function(self, dtime) - if exceptiondata.entity_step then - core.cause_error(exceptiondata.tocause) - end - end, -} -local exception_entity_name = "errorhandler_test:error_entity" - -local function exception_chat_handler(playername, param) - local parameters = param:split(" ") - - if #parameters ~= 2 then - core.chat_send_player(playername, "Invalid argument count for exceptiontest") - end - - core.log("error", "Causing error at:" .. parameters[1]) - - if parameters[1] == "mapgen" then - exceptiondata.tocause = parameters[2] - exceptiondata.mapgen = true - elseif parameters[1] == "entity_step" then - --spawn entity at player location - local player = core.get_player_by_name(playername) - - if player:is_player() then - local pos = player:getpos() - - core.add_entity(pos, exception_entity_name) - end - - exceptiondata.tocause = parameters[2] - exceptiondata.entity_step = true - - elseif parameters[1] == "globalstep" then - exceptiondata.tocause = parameters[2] - exceptiondata.globalstep = true - - elseif parameters[1] == "immediate" then - core.cause_error(parameters[2]) - - else - core.chat_send_player(playername, "Invalid error location: " .. dump(parameters[1])) - end -end - -core.register_chatcommand("exceptiontest", - { - params = " ", - description = "cause a given error to happen.\n" .. - " location=(mapgen,entity_step,globalstep,immediate)\n" .. - " errortype=(segv,zerodivision,exception)", - func = exception_chat_handler, - privs = { server=true } - }) - -core.register_globalstep(function(dtime) - if exceptiondata.globalstep then - core.cause_error(exceptiondata.tocause) - end -end) - -core.register_on_generated(function(minp, maxp, blockseed) - if exceptiondata.mapgen then - core.cause_error(exceptiondata.tocause) - end -end) - -core.register_entity(exception_entity_name, exception_entity) diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index 343d11b7e..6ac4bb653 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -483,36 +483,6 @@ int ModApiServer::l_set_last_run_mod(lua_State *L) return 0; } -#ifndef NDEBUG -// cause_error(type_of_error) -int ModApiServer::l_cause_error(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; - std::string type_of_error = "none"; - if(lua_isstring(L, 1)) - type_of_error = lua_tostring(L, 1); - - errorstream << "Error handler test called, errortype=" << type_of_error << std::endl; - - if(type_of_error == "segv") { - volatile int* some_pointer = 0; - errorstream << "Cause a sigsegv now: " << (*some_pointer) << std::endl; - - } else if (type_of_error == "zerodivision") { - - unsigned int some_number = porting::getTimeS(); - unsigned int zerovalue = 0; - unsigned int result = some_number / zerovalue; - errorstream << "Well this shouldn't ever be shown: " << result << std::endl; - - } else if (type_of_error == "exception") { - throw BaseException("Errorhandler test fct called"); - } - - return 0; -} -#endif - void ModApiServer::Initialize(lua_State *L, int top) { API_FCT(request_shutdown); @@ -545,7 +515,4 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(get_last_run_mod); API_FCT(set_last_run_mod); -#ifndef NDEBUG - API_FCT(cause_error); -#endif } diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h index ca5e7b80f..008810784 100644 --- a/src/script/lua_api/l_server.h +++ b/src/script/lua_api/l_server.h @@ -101,11 +101,6 @@ private: // set_last_run_mod(modname) static int l_set_last_run_mod(lua_State *L); -#ifndef NDEBUG - // cause_error(type_of_error) - static int l_cause_error(lua_State *L); -#endif - public: static void Initialize(lua_State *L, int top); }; -- cgit v1.2.3 From c1b3ed4180dea16e2fa77663a7d2bf155595dd60 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Sun, 7 May 2017 12:13:15 +0200 Subject: Player attrs: permits to remove an attribute by setting value to nil (#5716) * Player attrs: permits to remove an attribute by setting value to nil When doing player:set_attribute("attr", nil) remove attribute Also remove a useless check on C++ API part (already done by checkplayer) Fix #5709 --- doc/lua_api.txt | 4 +++- games/minimal/mods/default/init.lua | 22 ++++++++++++---------- src/content_sao.h | 10 ++++++++++ src/script/lua_api/l_object.cpp | 7 ++++--- 4 files changed, 29 insertions(+), 14 deletions(-) (limited to 'games') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 607a13fdd..d8e297f4c 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -3028,7 +3028,9 @@ This is basically a reference to a C++ `ServerActiveObject` * `0`: player is drowning, * `1`-`10`: remaining number of bubbles * `11`: bubbles bar is not shown -* `set_attribute(attribute, value)`: sets an extra attribute with value on player +* `set_attribute(attribute, value)`: + * Sets an extra attribute with value on player. + * If value is nil, remove attribute from player. * `get_attribute(attribute)`: returns value for extra attribute. Returns nil if no attribute found. * `set_inventory_formspec(formspec)` * Redefine player's inventory form diff --git a/games/minimal/mods/default/init.lua b/games/minimal/mods/default/init.lua index d36e225a3..64970f922 100644 --- a/games/minimal/mods/default/init.lua +++ b/games/minimal/mods/default/init.lua @@ -18,6 +18,8 @@ dofile(minetest.get_modpath("default").."/mapgen.lua") minetest.register_on_joinplayer(function(player) local cb = function(player) minetest.chat_send_player(player:get_player_name(), "This is the [minimal] \"Minimal Development Test\" game. Use [minetest_game] for the real thing.") + player:set_attribute("test_attribute", "test_me") + player:set_attribute("remove_this", nil) end minetest.after(2.0, cb, player) end) @@ -1387,13 +1389,13 @@ minetest.register_abm({ local srclist = inv:get_list("src") local cooked = nil - + if srclist then cooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist}) end - + local was_active = false - + if meta:get_float("fuel_time") < meta:get_float("fuel_totaltime") then was_active = true meta:set_float("fuel_time", meta:get_float("fuel_time") + 1) @@ -1413,7 +1415,7 @@ minetest.register_abm({ meta:set_string("src_time", 0) end end - + if meta:get_float("fuel_time") < meta:get_float("fuel_totaltime") then local percent = math.floor(meta:get_float("fuel_time") / meta:get_float("fuel_totaltime") * 100) @@ -1438,7 +1440,7 @@ minetest.register_abm({ local cooked = nil local fuellist = inv:get_list("fuel") local srclist = inv:get_list("src") - + if srclist then cooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist}) end @@ -1464,7 +1466,7 @@ minetest.register_abm({ meta:set_string("fuel_totaltime", fuel.time) meta:set_string("fuel_time", 0) - + local stack = inv:get_stack("fuel", 1) stack:take_item() inv:set_stack("fuel", 1, stack) @@ -1571,7 +1573,7 @@ function default.grow_tree(data, a, pos, is_apple_tree, seed) y = y+th-1 -- (x, y, z) is now last piece of trunk local leaves_a = VoxelArea:new{MinEdge={x=-2, y=-1, z=-2}, MaxEdge={x=2, y=2, z=2}} local leaves_buffer = {} - + -- Force leaves near the trunk local d = 1 for xi = -d, d do @@ -1581,14 +1583,14 @@ function default.grow_tree(data, a, pos, is_apple_tree, seed) end end end - + -- Add leaves randomly for iii = 1, 8 do local d = 1 local xx = pr:next(leaves_a.MinEdge.x, leaves_a.MaxEdge.x - d) local yy = pr:next(leaves_a.MinEdge.y, leaves_a.MaxEdge.y - d) local zz = pr:next(leaves_a.MinEdge.z, leaves_a.MaxEdge.z - d) - + for xi = 0, d do for yi = 0, d do for zi = 0, d do @@ -1597,7 +1599,7 @@ function default.grow_tree(data, a, pos, is_apple_tree, seed) end end end - + -- Add the leaves for xi = leaves_a.MinEdge.x, leaves_a.MaxEdge.x do for yi = leaves_a.MinEdge.y, leaves_a.MaxEdge.y do diff --git a/src/content_sao.h b/src/content_sao.h index e08795579..0dad54805 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -277,6 +277,16 @@ public: return true; } + inline void removeExtendedAttribute(const std::string &attr) + { + PlayerAttributes::iterator it = m_extra_attributes.find(attr); + if (it == m_extra_attributes.end()) + return; + + m_extra_attributes.erase(it); + m_extended_attributes_modified = true; + } + inline const PlayerAttributes &getExtendedAttributes() { return m_extra_attributes; diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 6f61ab55c..c7a31d048 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -1202,9 +1202,10 @@ int ObjectRef::l_set_attribute(lua_State *L) } std::string attr = luaL_checkstring(L, 2); - std::string value = luaL_checkstring(L, 3); - - if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER) { + if (lua_isnil(L, 3)) { + co->removeExtendedAttribute(attr); + } else { + std::string value = luaL_checkstring(L, 3); co->setExtendedAttribute(attr, value); } return 1; -- cgit v1.2.3 From 071e114ffa945522a7a9acc3259427166992d5ee Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 10 May 2017 15:29:21 +0200 Subject: Private nodemeta (#5702) * Private node metadata that isn't sent to the client --- doc/lua_api.txt | 4 ++ games/minimal/mods/default/init.lua | 2 + games/minimal/mods/experimental/init.lua | 10 ++++- src/mapblock.cpp | 7 ++-- src/nodemetadata.cpp | 63 +++++++++++++++++++++++++------- src/nodemetadata.h | 16 ++++++-- src/rollback_interface.cpp | 4 +- src/script/lua_api/l_nodemeta.cpp | 27 ++++++++++++++ src/script/lua_api/l_nodemeta.h | 3 ++ src/serialization.h | 5 ++- 10 files changed, 114 insertions(+), 27 deletions(-) (limited to 'games') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 901dd3c46..a295d7d0e 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -2895,6 +2895,10 @@ Can be obtained via `minetest.get_meta(pos)`. #### Methods * All methods in MetaDataRef * `get_inventory()`: returns `InvRef` +* `mark_as_private(name or {name1, name2, ...})`: Mark specific vars as private + This will prevent them from being sent to the client. Note that the "private" + status will only be remembered if an associated key-value pair exists, meaning + it's best to call this when initializing all other meta (e.g. on_construct). ### `ItemStackMetaRef` ItemStack metadata: reference extra data and functionality stored in a stack. diff --git a/games/minimal/mods/default/init.lua b/games/minimal/mods/default/init.lua index 64970f922..7d26f38a0 100644 --- a/games/minimal/mods/default/init.lua +++ b/games/minimal/mods/default/init.lua @@ -1228,6 +1228,8 @@ minetest.register_node("default:chest_locked", { meta:set_string("owner", "") local inv = meta:get_inventory() inv:set_size("main", 8*4) + -- this is not really the intended usage but works for testing purposes: + meta:mark_as_private("owner") end, can_dig = function(pos,player) local meta = minetest.get_meta(pos); diff --git a/games/minimal/mods/experimental/init.lua b/games/minimal/mods/experimental/init.lua index 5e98e1a80..6e0fb1738 100644 --- a/games/minimal/mods/experimental/init.lua +++ b/games/minimal/mods/experimental/init.lua @@ -502,10 +502,16 @@ minetest.register_craftitem("experimental:tester_tool_1", { on_use = function(itemstack, user, pointed_thing) --print(dump(pointed_thing)) if pointed_thing.type == "node" then - if minetest.get_node(pointed_thing.under).name == "experimental:tester_node_1" then + local node = minetest.get_node(pointed_thing.under) + if node.name == "experimental:tester_node_1" or node.name == "default:chest" then local p = pointed_thing.under minetest.log("action", "Tester tool used at "..minetest.pos_to_string(p)) - minetest.dig_node(p) + if node.name == "experimental:tester_node_1" then + minetest.dig_node(p) + else + minetest.get_meta(p):mark_as_private({"infotext", "formspec"}) + minetest.chat_send_player(user:get_player_name(), "Verify that chest is unusable now.") + end else local p = pointed_thing.above minetest.log("action", "Tester tool used at "..minetest.pos_to_string(p)) diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 1a0b01f2b..ec10a49bb 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -611,7 +611,7 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk) Node metadata */ std::ostringstream oss(std::ios_base::binary); - m_node_metadata.serialize(oss); + m_node_metadata.serialize(oss, version, disk); compressZlib(oss.str(), os); /* @@ -669,11 +669,10 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk) u8 flags = readU8(is); is_underground = (flags & 0x01) ? true : false; m_day_night_differs = (flags & 0x02) ? true : false; - if (version < 27) { + if (version < 27) m_lighting_complete = 0xFFFF; - } else { + else m_lighting_complete = readU16(is); - } m_generated = (flags & 0x08) ? false : true; /* diff --git a/src/nodemetadata.cpp b/src/nodemetadata.cpp index 9b60cf33e..0e8195c34 100644 --- a/src/nodemetadata.cpp +++ b/src/nodemetadata.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "inventory.h" #include "log.h" #include "util/serialize.h" +#include "util/basic_macros.h" #include "constants.h" // MAP_BLOCKSIZE #include @@ -39,28 +40,38 @@ NodeMetadata::~NodeMetadata() delete m_inventory; } -void NodeMetadata::serialize(std::ostream &os) const +void NodeMetadata::serialize(std::ostream &os, u8 version, bool disk) const { - int num_vars = m_stringvars.size(); + int num_vars = disk ? m_stringvars.size() : countNonPrivate(); writeU32(os, num_vars); for (StringMap::const_iterator it = m_stringvars.begin(); it != m_stringvars.end(); ++it) { + bool priv = isPrivate(it->first); + if (!disk && priv) + continue; + os << serializeString(it->first); os << serializeLongString(it->second); + if (version >= 2) + writeU8(os, (priv) ? 1 : 0); } m_inventory->serialize(os); } -void NodeMetadata::deSerialize(std::istream &is) +void NodeMetadata::deSerialize(std::istream &is, u8 version) { - m_stringvars.clear(); + clear(); int num_vars = readU32(is); for(int i=0; i= 2) { + if (readU8(is) == 1) + markPrivate(name, true); + } } m_inventory->deSerialize(is); @@ -69,6 +80,7 @@ void NodeMetadata::deSerialize(std::istream &is) void NodeMetadata::clear() { Metadata::clear(); + m_privatevars.clear(); m_inventory->clear(); } @@ -77,11 +89,34 @@ bool NodeMetadata::empty() const return Metadata::empty() && m_inventory->getLists().size() == 0; } + +void NodeMetadata::markPrivate(const std::string &name, bool set) +{ + if (set) + m_privatevars.insert(name); + else + m_privatevars.erase(name); +} + +int NodeMetadata::countNonPrivate() const +{ + // m_privatevars can contain names not actually present + // DON'T: return m_stringvars.size() - m_privatevars.size(); + int n = 0; + for (StringMap::const_iterator + it = m_stringvars.begin(); + it != m_stringvars.end(); ++it) { + if (isPrivate(it->first) == false) + n++; + } + return n; +} + /* NodeMetadataList */ -void NodeMetadataList::serialize(std::ostream &os) const +void NodeMetadataList::serialize(std::ostream &os, u8 blockver, bool disk) const { /* Version 0 is a placeholder for "nothing to see here; go away." @@ -93,7 +128,8 @@ void NodeMetadataList::serialize(std::ostream &os) const return; } - writeU8(os, 1); // version + u8 version = (blockver > 27) ? 2 : 1; + writeU8(os, version); writeU16(os, count); for(std::map::const_iterator @@ -108,7 +144,7 @@ void NodeMetadataList::serialize(std::ostream &os) const u16 p16 = p.Z * MAP_BLOCKSIZE * MAP_BLOCKSIZE + p.Y * MAP_BLOCKSIZE + p.X; writeU16(os, p16); - data->serialize(os); + data->serialize(os, version, disk); } } @@ -123,7 +159,7 @@ void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_m return; } - if (version != 1) { + if (version > 2) { std::string err_str = std::string(FUNCTION_NAME) + ": version " + itos(version) + " not supported"; infostream << err_str << std::endl; @@ -132,7 +168,7 @@ void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_m u16 count = readU16(is); - for (u16 i=0; i < count; i++) { + for (u16 i = 0; i < count; i++) { u16 p16 = readU16(is); v3s16 p; @@ -143,15 +179,14 @@ void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_m p.X = p16; if (m_data.find(p) != m_data.end()) { - warningstream<<"NodeMetadataList::deSerialize(): " - <<"already set data at position" - <<"("<deSerialize(is); + data->deSerialize(is, version); m_data[p] = data; } } diff --git a/src/nodemetadata.h b/src/nodemetadata.h index f46c0fe91..0d72485bc 100644 --- a/src/nodemetadata.h +++ b/src/nodemetadata.h @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define NODEMETADATA_HEADER #include "metadata.h" +#include "util/cpp11_container.h" /* NodeMetadata stores arbitary amounts of data for special blocks. @@ -40,8 +41,8 @@ public: NodeMetadata(IItemDefManager *item_def_mgr); ~NodeMetadata(); - void serialize(std::ostream &os) const; - void deSerialize(std::istream &is); + void serialize(std::ostream &os, u8 version, bool disk=true) const; + void deSerialize(std::istream &is, u8 version); void clear(); bool empty() const; @@ -52,8 +53,17 @@ public: return m_inventory; } + inline bool isPrivate(const std::string &name) const + { + return m_privatevars.count(name) != 0; + } + void markPrivate(const std::string &name, bool set); + private: + int countNonPrivate() const; + Inventory *m_inventory; + UNORDERED_SET m_privatevars; }; @@ -66,7 +76,7 @@ class NodeMetadataList public: ~NodeMetadataList(); - void serialize(std::ostream &os) const; + void serialize(std::ostream &os, u8 blockver, bool disk=true) const; void deSerialize(std::istream &is, IItemDefManager *item_def_mgr); // Add all keys in this list to the vector keys diff --git a/src/rollback_interface.cpp b/src/rollback_interface.cpp index 40a33a51d..d02d1cb3e 100644 --- a/src/rollback_interface.cpp +++ b/src/rollback_interface.cpp @@ -44,7 +44,7 @@ RollbackNode::RollbackNode(Map *map, v3s16 p, IGameDef *gamedef) NodeMetadata *metap = map->getNodeMetadata(p); if (metap) { std::ostringstream os(std::ios::binary); - metap->serialize(os); + metap->serialize(os, 1); // FIXME: version bump?? meta = os.str(); } } @@ -165,7 +165,7 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam } } std::istringstream is(n_old.meta, std::ios::binary); - meta->deSerialize(is); + meta->deSerialize(is, 1); // FIXME: version bump?? } // Inform other things that the meta data has changed v3s16 blockpos = getContainerPos(p, MAP_BLOCKSIZE); diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp index 6232112c5..5dfa6d52e 100644 --- a/src/script/lua_api/l_nodemeta.cpp +++ b/src/script/lua_api/l_nodemeta.cpp @@ -94,6 +94,32 @@ int NodeMetaRef::l_get_inventory(lua_State *L) return 1; } +// mark_as_private(self, or {, , ...}) +int NodeMetaRef::l_mark_as_private(lua_State *L) +{ + MAP_LOCK_REQUIRED; + + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = dynamic_cast(ref->getmeta(true)); + assert(meta); + + if (lua_istable(L, 2)) { + lua_pushnil(L); + while (lua_next(L, 2) != 0) { + // key at index -2 and value at index -1 + luaL_checktype(L, -1, LUA_TSTRING); + meta->markPrivate(lua_tostring(L, -1), true); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + } else if (lua_isstring(L, 2)) { + meta->markPrivate(lua_tostring(L, 2), true); + } + ref->reportMetadataChange(); + + return 0; +} + void NodeMetaRef::handleToTable(lua_State *L, Metadata *_meta) { // fields @@ -229,6 +255,7 @@ const luaL_Reg NodeMetaRef::methodsServer[] = { luamethod(MetaDataRef, to_table), luamethod(MetaDataRef, from_table), luamethod(NodeMetaRef, get_inventory), + luamethod(NodeMetaRef, mark_as_private), luamethod(MetaDataRef, equals), {0,0} }; diff --git a/src/script/lua_api/l_nodemeta.h b/src/script/lua_api/l_nodemeta.h index 2ac028079..dd4260ff9 100644 --- a/src/script/lua_api/l_nodemeta.h +++ b/src/script/lua_api/l_nodemeta.h @@ -73,6 +73,9 @@ private: // get_inventory(self) static int l_get_inventory(lua_State *L); + // mark_as_private(self, or {, , ...}) + static int l_mark_as_private(lua_State *L); + public: NodeMetaRef(v3s16 p, ServerEnvironment *env); NodeMetaRef(Metadata *meta); diff --git a/src/serialization.h b/src/serialization.h index 52c63098e..c91c3241f 100644 --- a/src/serialization.h +++ b/src/serialization.h @@ -63,13 +63,14 @@ with this program; if not, write to the Free Software Foundation, Inc., 25: Improved node timer format 26: Never written; read the same as 25 27: Added light spreading flags to blocks + 28: Added "private" flag to NodeMetadata */ // This represents an uninitialized or invalid format #define SER_FMT_VER_INVALID 255 // Highest supported serialization version -#define SER_FMT_VER_HIGHEST_READ 27 +#define SER_FMT_VER_HIGHEST_READ 28 // Saved on disk version -#define SER_FMT_VER_HIGHEST_WRITE 27 +#define SER_FMT_VER_HIGHEST_WRITE 28 // Lowest supported serialization version #define SER_FMT_VER_LOWEST_READ 0 // Lowest serialization version for writing -- cgit v1.2.3 From 649f641f28dcb5054131d98f76584e5579d9f6d5 Mon Sep 17 00:00:00 2001 From: Paramat Date: Wed, 24 May 2017 06:43:17 +0100 Subject: Minimal: Add river water nodes (#5809) Is a base terrain node needed by any core mapgen with sloping rivers. --- games/minimal/mods/default/init.lua | 79 ++++++++++++++++++--- games/minimal/mods/default/mapgen.lua | 1 + .../mods/default/textures/default_river_water.png | Bin 0 -> 716 bytes 3 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 games/minimal/mods/default/textures/default_river_water.png (limited to 'games') diff --git a/games/minimal/mods/default/init.lua b/games/minimal/mods/default/init.lua index 7d26f38a0..fcdf93547 100644 --- a/games/minimal/mods/default/init.lua +++ b/games/minimal/mods/default/init.lua @@ -992,37 +992,37 @@ minetest.register_node("default:cloud", { minetest.register_node("default:water_flowing", { description = "Water (flowing)", - inventory_image = minetest.inventorycube("default_water.png"), drawtype = "flowingliquid", - tiles ={"default_water.png"}, + tiles = {"default_water.png"}, special_tiles = { - {name="default_water.png", backface_culling=false}, - {name="default_water.png", backface_culling=true}, + {name = "default_water.png", backface_culling = false}, + {name = "default_water.png", backface_culling = true}, }, alpha = WATER_ALPHA, paramtype = "light", + paramtype2 = "flowingliquid", walkable = false, pointable = false, diggable = false, buildable_to = true, is_ground_content = false, + drop = "", drowning = 1, liquidtype = "flowing", liquid_alternative_flowing = "default:water_flowing", liquid_alternative_source = "default:water_source", liquid_viscosity = WATER_VISC, - post_effect_color = {a=64, r=100, g=100, b=200}, - groups = {water=3, liquid=3}, + post_effect_color = {a = 64, r = 100, g = 100, b = 200}, + groups = {water = 3, liquid = 3}, }) minetest.register_node("default:water_source", { description = "Water", - inventory_image = minetest.inventorycube("default_water.png"), drawtype = "liquid", - tiles ={"default_water.png"}, + tiles = {"default_water.png"}, special_tiles = { -- New-style water source material (mostly unused) - {name="default_water.png", backface_culling=false}, + {name = "default_water.png", backface_culling = false}, }, alpha = WATER_ALPHA, paramtype = "light", @@ -1031,13 +1031,70 @@ minetest.register_node("default:water_source", { diggable = false, buildable_to = true, is_ground_content = false, + drop = "", drowning = 1, liquidtype = "source", liquid_alternative_flowing = "default:water_flowing", liquid_alternative_source = "default:water_source", liquid_viscosity = WATER_VISC, - post_effect_color = {a=64, r=100, g=100, b=200}, - groups = {water=3, liquid=3}, + post_effect_color = {a = 64, r = 100, g = 100, b = 200}, + groups = {water = 3, liquid = 3}, +}) + +minetest.register_node("default:river_water_source", { + description = "River Water Source", + drawtype = "liquid", + tiles = {"default_river_water.png"}, + special_tiles = { + -- New-style water source material (mostly unused) + {name = "default_river_water.png", backface_culling = false}, + }, + alpha = 160, + paramtype = "light", + walkable = false, + pointable = false, + diggable = false, + buildable_to = true, + is_ground_content = false, + drop = "", + drowning = 1, + liquidtype = "source", + liquid_alternative_flowing = "default:river_water_flowing", + liquid_alternative_source = "default:river_water_source", + liquid_viscosity = 1, + liquid_renewable = false, + liquid_range = 2, + post_effect_color = {a = 103, r = 30, g = 76, b = 90}, + groups = {water = 3, liquid = 3, puts_out_fire = 1, cools_lava = 1}, +}) + +minetest.register_node("default:river_water_flowing", { + description = "Flowing River Water", + drawtype = "flowingliquid", + tiles = {"default_river_water.png"}, + special_tiles = { + {name = "default_river_water.png", backface_culling = false}, + {name = "default_river_water.png", backface_culling = true}, + }, + alpha = 160, + paramtype = "light", + paramtype2 = "flowingliquid", + walkable = false, + pointable = false, + diggable = false, + buildable_to = true, + is_ground_content = false, + drop = "", + drowning = 1, + liquidtype = "flowing", + liquid_alternative_flowing = "default:river_water_flowing", + liquid_alternative_source = "default:river_water_source", + liquid_viscosity = 1, + liquid_renewable = false, + liquid_range = 2, + post_effect_color = {a = 103, r = 30, g = 76, b = 90}, + groups = {water = 3, liquid = 3, puts_out_fire = 1, + not_in_creative_inventory = 1, cools_lava = 1}, }) minetest.register_node("default:lava_flowing", { diff --git a/games/minimal/mods/default/mapgen.lua b/games/minimal/mods/default/mapgen.lua index 65b67dae5..30a865366 100644 --- a/games/minimal/mods/default/mapgen.lua +++ b/games/minimal/mods/default/mapgen.lua @@ -8,6 +8,7 @@ minetest.register_alias("mapgen_dirt", "default:dirt") minetest.register_alias("mapgen_dirt_with_grass", "default:dirt_with_grass") minetest.register_alias("mapgen_sand", "default:sand") minetest.register_alias("mapgen_water_source", "default:water_source") +minetest.register_alias("mapgen_river_water_source", "default:river_water_source") minetest.register_alias("mapgen_lava_source", "default:lava_source") minetest.register_alias("mapgen_gravel", "default:gravel") diff --git a/games/minimal/mods/default/textures/default_river_water.png b/games/minimal/mods/default/textures/default_river_water.png new file mode 100644 index 000000000..3b55c5f66 Binary files /dev/null and b/games/minimal/mods/default/textures/default_river_water.png differ -- cgit v1.2.3