Compare commits
21 Commits
0.4.dev-20
...
0.4.dev-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdf7b3bcdf | ||
|
|
871e6c0c73 | ||
|
|
392485aa45 | ||
|
|
275a348b75 | ||
|
|
189689716c | ||
|
|
3965d432ca | ||
|
|
746b960c0d | ||
|
|
760416b81f | ||
|
|
1c785c32ef | ||
|
|
cd608b1877 | ||
|
|
c6dd75ccfb | ||
|
|
6b2023dc3e | ||
|
|
2f4a92d701 | ||
|
|
324c544922 | ||
|
|
fbbbcf97d8 | ||
|
|
d96cd236f3 | ||
|
|
581f950e10 | ||
|
|
9344816bd6 | ||
|
|
67c21fc42f | ||
|
|
c2d266efc6 | ||
|
|
ec1859b095 |
@@ -10,7 +10,7 @@ project(minetest)
|
||||
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
|
||||
set(VERSION_MAJOR 0)
|
||||
set(VERSION_MINOR 4)
|
||||
set(VERSION_PATCH dev-20111202-1)
|
||||
set(VERSION_PATCH dev-20111203-3)
|
||||
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
||||
|
||||
MESSAGE(STATUS "*** Will build version ${VERSION_STRING} ***")
|
||||
|
||||
@@ -303,6 +303,19 @@ function test_stackstring()
|
||||
end
|
||||
test_stackstring()
|
||||
|
||||
--
|
||||
-- nodeitem helpers
|
||||
--
|
||||
|
||||
minetest.inventorycube = function(img1, img2, img3)
|
||||
img2 = img2 or img1
|
||||
img3 = img3 or img1
|
||||
return "[inventorycube"
|
||||
.. "{" .. img1:gsub("%^", "&")
|
||||
.. "{" .. img2:gsub("%^", "&")
|
||||
.. "{" .. img3:gsub("%^", "&")
|
||||
end
|
||||
|
||||
--
|
||||
-- craftitem helpers
|
||||
--
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
minetest.register_craft({
|
||||
output = 'craft "bucket" 1',
|
||||
output = 'craft "bucket:bucket_empty" 1',
|
||||
recipe = {
|
||||
{'craft "steel_ingot"', '', 'craft "steel_ingot"'},
|
||||
{'', 'craft "steel_ingot"', ''},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craftitem("bucket", {
|
||||
minetest.register_craftitem("bucket:bucket_empty", {
|
||||
image = "bucket.png",
|
||||
stack_max = 1,
|
||||
liquids_pointable = true,
|
||||
@@ -16,11 +16,11 @@ minetest.register_craftitem("bucket", {
|
||||
n = minetest.env:get_node(pointed_thing.under)
|
||||
if n.name == "water_source" then
|
||||
minetest.env:add_node(pointed_thing.under, {name="air"})
|
||||
player:add_to_inventory_later('craft "bucket_water" 1')
|
||||
player:add_to_inventory_later('craft "bucket:bucket_water" 1')
|
||||
return true
|
||||
elseif n.name == "lava_source" then
|
||||
minetest.env:add_node(pointed_thing.under, {name="air"})
|
||||
player:add_to_inventory_later('craft "bucket_lava" 1')
|
||||
player:add_to_inventory_later('craft "bucket:bucket_lava" 1')
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -28,8 +28,8 @@ minetest.register_craftitem("bucket", {
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("bucket_water", {
|
||||
image = "bucket_water.png",
|
||||
minetest.register_craftitem("bucket:bucket_water", {
|
||||
image = "bucket:bucket_water.png",
|
||||
stack_max = 1,
|
||||
liquids_pointable = true,
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
@@ -43,15 +43,15 @@ minetest.register_craftitem("bucket_water", {
|
||||
else
|
||||
minetest.env:add_node(pointed_thing.above, {name="water_source"})
|
||||
end
|
||||
player:add_to_inventory_later('craft "bucket" 1')
|
||||
player:add_to_inventory_later('craft "bucket:bucket_empty" 1')
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("bucket_lava", {
|
||||
image = "bucket_lava.png",
|
||||
minetest.register_craftitem("bucket:bucket_lava", {
|
||||
image = "bucket:bucket_lava.png",
|
||||
stack_max = 1,
|
||||
liquids_pointable = true,
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
@@ -65,7 +65,7 @@ minetest.register_craftitem("bucket_lava", {
|
||||
else
|
||||
minetest.env:add_node(pointed_thing.above, {name="lava_source"})
|
||||
end
|
||||
player:add_to_inventory_later('craft "bucket" 1')
|
||||
player:add_to_inventory_later('craft "bucket:bucket_empty" 1')
|
||||
return true
|
||||
end
|
||||
return false
|
||||
|
||||
@@ -2,10 +2,51 @@
|
||||
-- dump2(obj, name="_", dumped={})
|
||||
-- dump(obj, dumped={})
|
||||
--
|
||||
-- Textures:
|
||||
-- Mods should prefix their textures with modname_, eg. given the mod
|
||||
-- name "foomod", a texture could be called "foomod_superfurnace.png"
|
||||
-- Due to historical reasons, the default mod does not follow this rule.
|
||||
-- Mod load path
|
||||
-- -------------
|
||||
-- Generic:
|
||||
-- $path_data/mods/
|
||||
-- $path_userdata/usermods/
|
||||
-- $mapdir/worldmods/
|
||||
--
|
||||
-- On a run-in-place version (eg. the distributed windows version):
|
||||
-- minetest-0.4.x/data/mods/
|
||||
-- minetest-0.4.x/usermods/
|
||||
-- minetest-0.4.x/world/worldmods/
|
||||
--
|
||||
-- On an installed version on linux:
|
||||
-- /usr/share/minetest/mods/
|
||||
-- ~/.minetest/usermods
|
||||
-- ~/.minetest/world/worldmods
|
||||
--
|
||||
-- Naming convention for registered textual names
|
||||
-- ----------------------------------------------
|
||||
-- "modname:<whatever>" (<whatever> can have characters a-zA-Z0-9_)
|
||||
--
|
||||
-- This is to prevent conflicting names from corrupting maps and is
|
||||
-- enforced by the mod loader.
|
||||
--
|
||||
-- Example: mod "experimental", ideal item/node/entity name "tnt":
|
||||
-- -> the name should be "experimental:tnt".
|
||||
--
|
||||
-- Enforcement can be overridden by prefixing the name with ":". This can
|
||||
-- be used for overriding the registrations of some other mod.
|
||||
--
|
||||
-- Example: Any mod can redefine experimental:tnt by using the name
|
||||
-- ":experimental:tnt" when registering it.
|
||||
-- (also that mods is required to have "experimental" as a dependency)
|
||||
--
|
||||
-- Default mod uses ":" for maintaining backwards compatibility.
|
||||
--
|
||||
-- Textures
|
||||
-- --------
|
||||
-- Mods should generally prefix their textures with modname_, eg. given
|
||||
-- the mod name "foomod", a texture could be called "foomod_superfurnace.png"
|
||||
--
|
||||
-- This is not crucial and a conflicting name will not corrupt maps.
|
||||
--
|
||||
-- Representations of simple things
|
||||
-- --------------------------------
|
||||
--
|
||||
-- MapNode representation:
|
||||
-- {name="name", param1=num, param2=num}
|
||||
@@ -220,7 +261,7 @@
|
||||
-- }
|
||||
--
|
||||
-- Craftitem definition options:
|
||||
-- minetest.register_craftitem("name", {
|
||||
-- minetest.register_craftitem("modname_name", {
|
||||
-- image = "image.png",
|
||||
-- stack_max = <maximum number of items in stack>,
|
||||
-- cookresult_item = itemstring (result of cooking),
|
||||
@@ -256,7 +297,7 @@ LIGHT_MAX = 14
|
||||
-- Tool definition
|
||||
--
|
||||
|
||||
minetest.register_tool("WPick", {
|
||||
minetest.register_tool(":WPick", {
|
||||
image = "tool_woodpick.png",
|
||||
basetime = 2.0,
|
||||
dt_weight = 0,
|
||||
@@ -269,7 +310,7 @@ minetest.register_tool("WPick", {
|
||||
dd_crumbliness = 0,
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
minetest.register_tool("STPick", {
|
||||
minetest.register_tool(":STPick", {
|
||||
image = "tool_stonepick.png",
|
||||
basetime = 1.5,
|
||||
dt_weight = 0,
|
||||
@@ -282,7 +323,7 @@ minetest.register_tool("STPick", {
|
||||
dd_crumbliness = 0,
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
minetest.register_tool("SteelPick", {
|
||||
minetest.register_tool(":SteelPick", {
|
||||
image = "tool_steelpick.png",
|
||||
basetime = 1.0,
|
||||
dt_weight = 0,
|
||||
@@ -295,7 +336,7 @@ minetest.register_tool("SteelPick", {
|
||||
dd_crumbliness = 0,
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
minetest.register_tool("MesePick", {
|
||||
minetest.register_tool(":MesePick", {
|
||||
image = "tool_mesepick.png",
|
||||
basetime = 0,
|
||||
dt_weight = 0,
|
||||
@@ -308,7 +349,7 @@ minetest.register_tool("MesePick", {
|
||||
dd_crumbliness = 0,
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
minetest.register_tool("WShovel", {
|
||||
minetest.register_tool(":WShovel", {
|
||||
image = "tool_woodshovel.png",
|
||||
basetime = 2.0,
|
||||
dt_weight = 0.5,
|
||||
@@ -321,7 +362,7 @@ minetest.register_tool("WShovel", {
|
||||
dd_crumbliness = 0,
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
minetest.register_tool("STShovel", {
|
||||
minetest.register_tool(":STShovel", {
|
||||
image = "tool_stoneshovel.png",
|
||||
basetime = 1.5,
|
||||
dt_weight = 0.5,
|
||||
@@ -334,7 +375,7 @@ minetest.register_tool("STShovel", {
|
||||
dd_crumbliness = 0,
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
minetest.register_tool("SteelShovel", {
|
||||
minetest.register_tool(":SteelShovel", {
|
||||
image = "tool_steelshovel.png",
|
||||
basetime = 1.0,
|
||||
dt_weight = 0.5,
|
||||
@@ -347,7 +388,7 @@ minetest.register_tool("SteelShovel", {
|
||||
dd_crumbliness = 0,
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
minetest.register_tool("WAxe", {
|
||||
minetest.register_tool(":WAxe", {
|
||||
image = "tool_woodaxe.png",
|
||||
basetime = 2.0,
|
||||
dt_weight = 0.5,
|
||||
@@ -360,7 +401,7 @@ minetest.register_tool("WAxe", {
|
||||
dd_crumbliness = 0,
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
minetest.register_tool("STAxe", {
|
||||
minetest.register_tool(":STAxe", {
|
||||
image = "tool_stoneaxe.png",
|
||||
basetime = 1.5,
|
||||
dt_weight = 0.5,
|
||||
@@ -373,7 +414,7 @@ minetest.register_tool("STAxe", {
|
||||
dd_crumbliness = 0,
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
minetest.register_tool("SteelAxe", {
|
||||
minetest.register_tool(":SteelAxe", {
|
||||
image = "tool_steelaxe.png",
|
||||
basetime = 1.0,
|
||||
dt_weight = 0.5,
|
||||
@@ -386,7 +427,7 @@ minetest.register_tool("SteelAxe", {
|
||||
dd_crumbliness = 0,
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
minetest.register_tool("WSword", {
|
||||
minetest.register_tool(":WSword", {
|
||||
image = "tool_woodsword.png",
|
||||
basetime = 3.0,
|
||||
dt_weight = 3,
|
||||
@@ -399,7 +440,7 @@ minetest.register_tool("WSword", {
|
||||
dd_crumbliness = 0,
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
minetest.register_tool("STSword", {
|
||||
minetest.register_tool(":STSword", {
|
||||
image = "tool_stonesword.png",
|
||||
basetime = 2.5,
|
||||
dt_weight = 3,
|
||||
@@ -412,7 +453,7 @@ minetest.register_tool("STSword", {
|
||||
dd_crumbliness = 0,
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
minetest.register_tool("SteelSword", {
|
||||
minetest.register_tool(":SteelSword", {
|
||||
image = "tool_steelsword.png",
|
||||
basetime = 2.0,
|
||||
dt_weight = 3,
|
||||
@@ -426,7 +467,7 @@ minetest.register_tool("SteelSword", {
|
||||
dd_cuttability = 0,
|
||||
})
|
||||
-- The hand
|
||||
minetest.register_tool("", {
|
||||
minetest.register_tool(":", {
|
||||
image = "",
|
||||
basetime = 0.5,
|
||||
dt_weight = 1,
|
||||
@@ -783,20 +824,11 @@ function digprop_glasslike(toughness)
|
||||
}
|
||||
end
|
||||
|
||||
function inventorycube(img1, img2, img3)
|
||||
img2 = img2 or img1
|
||||
img3 = img3 or img1
|
||||
return "[inventorycube"
|
||||
.. "{" .. img1:gsub("%^", "&")
|
||||
.. "{" .. img2:gsub("%^", "&")
|
||||
.. "{" .. img3:gsub("%^", "&")
|
||||
end
|
||||
|
||||
-- Legacy nodes
|
||||
|
||||
minetest.register_node("stone", {
|
||||
minetest.register_node(":stone", {
|
||||
tile_images = {"stone.png"},
|
||||
inventory_image = inventorycube("stone.png"),
|
||||
inventory_image = minetest.inventorycube("stone.png"),
|
||||
paramtype = "mineral",
|
||||
is_ground_content = true,
|
||||
often_contains_mineral = true, -- Texture atlas hint
|
||||
@@ -804,15 +836,15 @@ minetest.register_node("stone", {
|
||||
dug_item = 'node "cobble" 1',
|
||||
})
|
||||
|
||||
minetest.register_node("dirt_with_grass", {
|
||||
minetest.register_node(":dirt_with_grass", {
|
||||
tile_images = {"grass.png", "mud.png", "mud.png^grass_side.png"},
|
||||
inventory_image = inventorycube("mud.png^grass_side.png"),
|
||||
inventory_image = minetest.inventorycube("mud.png^grass_side.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_dirtlike(1.0),
|
||||
dug_item = 'node "dirt" 1',
|
||||
})
|
||||
|
||||
minetest.register_node("dirt_with_grass_footsteps", {
|
||||
minetest.register_node(":dirt_with_grass_footsteps", {
|
||||
tile_images = {"grass_footsteps.png", "mud.png", "mud.png^grass_side.png"},
|
||||
inventory_image = "grass_footsteps.png",
|
||||
is_ground_content = true,
|
||||
@@ -820,71 +852,71 @@ minetest.register_node("dirt_with_grass_footsteps", {
|
||||
dug_item = 'node "dirt" 1',
|
||||
})
|
||||
|
||||
minetest.register_node("dirt", {
|
||||
minetest.register_node(":dirt", {
|
||||
tile_images = {"mud.png"},
|
||||
inventory_image = inventorycube("mud.png"),
|
||||
inventory_image = minetest.inventorycube("mud.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_dirtlike(1.0),
|
||||
})
|
||||
|
||||
minetest.register_node("sand", {
|
||||
minetest.register_node(":sand", {
|
||||
tile_images = {"sand.png"},
|
||||
inventory_image = inventorycube("sand.png"),
|
||||
inventory_image = minetest.inventorycube("sand.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_dirtlike(1.0),
|
||||
cookresult_item = 'node "glass" 1',
|
||||
})
|
||||
|
||||
minetest.register_node("gravel", {
|
||||
minetest.register_node(":gravel", {
|
||||
tile_images = {"gravel.png"},
|
||||
inventory_image = inventorycube("gravel.png"),
|
||||
inventory_image = minetest.inventorycube("gravel.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_gravellike(1.0),
|
||||
})
|
||||
|
||||
minetest.register_node("sandstone", {
|
||||
minetest.register_node(":sandstone", {
|
||||
tile_images = {"sandstone.png"},
|
||||
inventory_image = inventorycube("sandstone.png"),
|
||||
inventory_image = minetest.inventorycube("sandstone.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_dirtlike(1.0), -- FIXME should this be stonelike?
|
||||
dug_item = 'node "sand" 1', -- FIXME is this intentional?
|
||||
})
|
||||
|
||||
minetest.register_node("clay", {
|
||||
minetest.register_node(":clay", {
|
||||
tile_images = {"clay.png"},
|
||||
inventory_image = inventorycube("clay.png"),
|
||||
inventory_image = minetest.inventorycube("clay.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_dirtlike(1.0),
|
||||
dug_item = 'craft "lump_of_clay" 4',
|
||||
})
|
||||
|
||||
minetest.register_node("brick", {
|
||||
minetest.register_node(":brick", {
|
||||
tile_images = {"brick.png"},
|
||||
inventory_image = inventorycube("brick.png"),
|
||||
inventory_image = minetest.inventorycube("brick.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_stonelike(1.0),
|
||||
dug_item = 'craft "clay_brick" 4',
|
||||
})
|
||||
|
||||
minetest.register_node("tree", {
|
||||
minetest.register_node(":tree", {
|
||||
tile_images = {"tree_top.png", "tree_top.png", "tree.png"},
|
||||
inventory_image = inventorycube("tree_top.png", "tree.png", "tree.png"),
|
||||
inventory_image = minetest.inventorycube("tree_top.png", "tree.png", "tree.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_woodlike(1.0),
|
||||
cookresult_item = 'craft "lump_of_coal" 1',
|
||||
furnace_burntime = 30,
|
||||
})
|
||||
|
||||
minetest.register_node("jungletree", {
|
||||
minetest.register_node(":jungletree", {
|
||||
tile_images = {"jungletree_top.png", "jungletree_top.png", "jungletree.png"},
|
||||
inventory_image = inventorycube("jungletree_top.png", "jungletree.png", "jungletree.png"),
|
||||
inventory_image = minetest.inventorycube("jungletree_top.png", "jungletree.png", "jungletree.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_woodlike(1.0),
|
||||
cookresult_item = 'craft "lump_of_coal" 1',
|
||||
furnace_burntime = 30,
|
||||
})
|
||||
|
||||
minetest.register_node("junglegrass", {
|
||||
minetest.register_node(":junglegrass", {
|
||||
drawtype = "plantlike",
|
||||
visual_scale = 1.3,
|
||||
tile_images = {"junglegrass.png"},
|
||||
@@ -896,11 +928,11 @@ minetest.register_node("junglegrass", {
|
||||
furnace_burntime = 2,
|
||||
})
|
||||
|
||||
minetest.register_node("leaves", {
|
||||
minetest.register_node(":leaves", {
|
||||
drawtype = "allfaces_optional",
|
||||
visual_scale = 1.3,
|
||||
tile_images = {"leaves.png"},
|
||||
inventory_image = "leaves.png",
|
||||
inventory_image = minetest.inventorycube("leaves.png"),
|
||||
light_propagates = true,
|
||||
paramtype = "light",
|
||||
material = digprop_leaveslike(1.0),
|
||||
@@ -909,15 +941,15 @@ minetest.register_node("leaves", {
|
||||
furnace_burntime = 1,
|
||||
})
|
||||
|
||||
minetest.register_node("cactus", {
|
||||
minetest.register_node(":cactus", {
|
||||
tile_images = {"cactus_top.png", "cactus_top.png", "cactus_side.png"},
|
||||
inventory_image = inventorycube("cactus_top.png", "cactus_side.png", "cactus_side.png"),
|
||||
inventory_image = minetest.inventorycube("cactus_top.png", "cactus_side.png", "cactus_side.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_woodlike(0.75),
|
||||
furnace_burntime = 15,
|
||||
})
|
||||
|
||||
minetest.register_node("papyrus", {
|
||||
minetest.register_node(":papyrus", {
|
||||
drawtype = "plantlike",
|
||||
tile_images = {"papyrus.png"},
|
||||
inventory_image = "papyrus.png",
|
||||
@@ -929,20 +961,18 @@ minetest.register_node("papyrus", {
|
||||
furnace_burntime = 1,
|
||||
})
|
||||
|
||||
minetest.register_node("bookshelf", {
|
||||
minetest.register_node(":bookshelf", {
|
||||
tile_images = {"wood.png", "wood.png", "bookshelf.png"},
|
||||
-- FIXME: inventorycube only cares for the first texture
|
||||
--inventory_image = inventorycube("wood.png", "bookshelf.png", "bookshelf.png")
|
||||
inventory_image = inventorycube("bookshelf.png"),
|
||||
inventory_image = minetest.inventorycube("wood.png", "bookshelf.png", "bookshelf.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_woodlike(0.75),
|
||||
furnace_burntime = 30,
|
||||
})
|
||||
|
||||
minetest.register_node("glass", {
|
||||
minetest.register_node(":glass", {
|
||||
drawtype = "glasslike",
|
||||
tile_images = {"glass.png"},
|
||||
inventory_image = inventorycube("glass.png"),
|
||||
inventory_image = minetest.inventorycube("glass.png"),
|
||||
light_propagates = true,
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
@@ -950,7 +980,7 @@ minetest.register_node("glass", {
|
||||
material = digprop_glasslike(1.0),
|
||||
})
|
||||
|
||||
minetest.register_node("wooden_fence", {
|
||||
minetest.register_node(":wooden_fence", {
|
||||
drawtype = "fencelike",
|
||||
tile_images = {"wood.png"},
|
||||
inventory_image = "fence.png",
|
||||
@@ -965,7 +995,7 @@ minetest.register_node("wooden_fence", {
|
||||
material = digprop_woodlike(0.75),
|
||||
})
|
||||
|
||||
minetest.register_node("rail", {
|
||||
minetest.register_node(":rail", {
|
||||
drawtype = "raillike",
|
||||
tile_images = {"rail.png", "rail_curved.png", "rail_t_junction.png", "rail_crossing.png"},
|
||||
inventory_image = "rail.png",
|
||||
@@ -980,7 +1010,7 @@ minetest.register_node("rail", {
|
||||
material = digprop_dirtlike(0.75),
|
||||
})
|
||||
|
||||
minetest.register_node("ladder", {
|
||||
minetest.register_node(":ladder", {
|
||||
drawtype = "signlike",
|
||||
tile_images = {"ladder.png"},
|
||||
inventory_image = "ladder.png",
|
||||
@@ -1000,40 +1030,40 @@ minetest.register_node("ladder", {
|
||||
material = digprop_woodlike(0.5),
|
||||
})
|
||||
|
||||
minetest.register_node("coalstone", {
|
||||
minetest.register_node(":coalstone", {
|
||||
tile_images = {"stone.png^mineral_coal.png"},
|
||||
inventory_image = "stone.png^mineral_coal.png",
|
||||
is_ground_content = true,
|
||||
material = digprop_stonelike(1.5),
|
||||
})
|
||||
|
||||
minetest.register_node("wood", {
|
||||
minetest.register_node(":wood", {
|
||||
tile_images = {"wood.png"},
|
||||
inventory_image = inventorycube("wood.png"),
|
||||
inventory_image = minetest.inventorycube("wood.png"),
|
||||
is_ground_content = true,
|
||||
furnace_burntime = 7,
|
||||
material = digprop_woodlike(0.75),
|
||||
})
|
||||
|
||||
minetest.register_node("mese", {
|
||||
minetest.register_node(":mese", {
|
||||
tile_images = {"mese.png"},
|
||||
inventory_image = inventorycube("mese.png"),
|
||||
inventory_image = minetest.inventorycube("mese.png"),
|
||||
is_ground_content = true,
|
||||
furnace_burntime = 30,
|
||||
material = digprop_stonelike(0.5),
|
||||
})
|
||||
|
||||
minetest.register_node("cloud", {
|
||||
minetest.register_node(":cloud", {
|
||||
tile_images = {"cloud.png"},
|
||||
inventory_image = inventorycube("cloud.png"),
|
||||
inventory_image = minetest.inventorycube("cloud.png"),
|
||||
is_ground_content = true,
|
||||
})
|
||||
|
||||
minetest.register_node("water_flowing", {
|
||||
minetest.register_node(":water_flowing", {
|
||||
drawtype = "flowingliquid",
|
||||
tile_images = {"water.png"},
|
||||
alpha = WATER_ALPHA,
|
||||
inventory_image = inventorycube("water.png"),
|
||||
inventory_image = minetest.inventorycube("water.png"),
|
||||
paramtype = "light",
|
||||
light_propagates = true,
|
||||
walkable = false,
|
||||
@@ -1051,11 +1081,11 @@ minetest.register_node("water_flowing", {
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_node("water_source", {
|
||||
minetest.register_node(":water_source", {
|
||||
drawtype = "liquid",
|
||||
tile_images = {"water.png"},
|
||||
alpha = WATER_ALPHA,
|
||||
inventory_image = inventorycube("water.png"),
|
||||
inventory_image = minetest.inventorycube("water.png"),
|
||||
paramtype = "light",
|
||||
light_propagates = true,
|
||||
walkable = false,
|
||||
@@ -1073,10 +1103,10 @@ minetest.register_node("water_source", {
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_node("lava_flowing", {
|
||||
minetest.register_node(":lava_flowing", {
|
||||
drawtype = "flowingliquid",
|
||||
tile_images = {"lava.png"},
|
||||
inventory_image = inventorycube("lava.png"),
|
||||
inventory_image = minetest.inventorycube("lava.png"),
|
||||
paramtype = "light",
|
||||
light_propagates = false,
|
||||
light_source = LIGHT_MAX - 1,
|
||||
@@ -1096,10 +1126,10 @@ minetest.register_node("lava_flowing", {
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_node("lava_source", {
|
||||
minetest.register_node(":lava_source", {
|
||||
drawtype = "liquid",
|
||||
tile_images = {"lava.png"},
|
||||
inventory_image = inventorycube("lava.png"),
|
||||
inventory_image = minetest.inventorycube("lava.png"),
|
||||
paramtype = "light",
|
||||
light_propagates = false,
|
||||
light_source = LIGHT_MAX - 1,
|
||||
@@ -1120,7 +1150,7 @@ minetest.register_node("lava_source", {
|
||||
furnace_burntime = 60,
|
||||
})
|
||||
|
||||
minetest.register_node("torch", {
|
||||
minetest.register_node(":torch", {
|
||||
drawtype = "torchlike",
|
||||
tile_images = {"torch_on_floor.png", "torch_on_ceiling.png", "torch.png"},
|
||||
inventory_image = "torch_on_floor.png",
|
||||
@@ -1140,7 +1170,7 @@ minetest.register_node("torch", {
|
||||
furnace_burntime = 4,
|
||||
})
|
||||
|
||||
minetest.register_node("sign_wall", {
|
||||
minetest.register_node(":sign_wall", {
|
||||
drawtype = "signlike",
|
||||
tile_images = {"sign_wall.png"},
|
||||
inventory_image = "sign_wall.png",
|
||||
@@ -1160,59 +1190,58 @@ minetest.register_node("sign_wall", {
|
||||
furnace_burntime = 10,
|
||||
})
|
||||
|
||||
minetest.register_node("chest", {
|
||||
minetest.register_node(":chest", {
|
||||
tile_images = {"chest_top.png", "chest_top.png", "chest_side.png",
|
||||
"chest_side.png", "chest_side.png", "chest_front.png"},
|
||||
inventory_image = "chest_top.png",
|
||||
--inventory_image = inventorycube("chest_top.png", "chest_side.png", "chest_front.png"),
|
||||
inventory_image = minetest.inventorycube("chest_top.png", "chest_front.png", "chest_side.png"),
|
||||
paramtype = "facedir_simple",
|
||||
metadata_name = "chest",
|
||||
material = digprop_woodlike(1.0),
|
||||
furnace_burntime = 30,
|
||||
})
|
||||
|
||||
minetest.register_node("locked_chest", {
|
||||
minetest.register_node(":locked_chest", {
|
||||
tile_images = {"chest_top.png", "chest_top.png", "chest_side.png",
|
||||
"chest_side.png", "chest_side.png", "chest_lock.png"},
|
||||
inventory_image = "chest_lock.png",
|
||||
inventory_image = minetest.inventorycube("chest_top.png", "chest_lock.png", "chest_side.png"),
|
||||
paramtype = "facedir_simple",
|
||||
metadata_name = "locked_chest",
|
||||
material = digprop_woodlike(1.0),
|
||||
furnace_burntime = 30,
|
||||
})
|
||||
|
||||
minetest.register_node("furnace", {
|
||||
minetest.register_node(":furnace", {
|
||||
tile_images = {"furnace_side.png", "furnace_side.png", "furnace_side.png",
|
||||
"furnace_side.png", "furnace_side.png", "furnace_front.png"},
|
||||
inventory_image = "furnace_front.png",
|
||||
inventory_image = minetest.inventorycube("furnace_side.png", "furnace_front.png", "furnace_side.png"),
|
||||
paramtype = "facedir_simple",
|
||||
metadata_name = "furnace",
|
||||
material = digprop_stonelike(3.0),
|
||||
})
|
||||
|
||||
minetest.register_node("cobble", {
|
||||
minetest.register_node(":cobble", {
|
||||
tile_images = {"cobble.png"},
|
||||
inventory_image = inventorycube("cobble.png"),
|
||||
inventory_image = minetest.inventorycube("cobble.png"),
|
||||
is_ground_content = true,
|
||||
cookresult_item = 'node "stone" 1',
|
||||
material = digprop_stonelike(0.9),
|
||||
})
|
||||
|
||||
minetest.register_node("mossycobble", {
|
||||
minetest.register_node(":mossycobble", {
|
||||
tile_images = {"mossycobble.png"},
|
||||
inventory_image = inventorycube("mossycobble.png"),
|
||||
inventory_image = minetest.inventorycube("mossycobble.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_stonelike(0.8),
|
||||
})
|
||||
|
||||
minetest.register_node("steelblock", {
|
||||
minetest.register_node(":steelblock", {
|
||||
tile_images = {"steel_block.png"},
|
||||
inventory_image = inventorycube("steel_block.png"),
|
||||
inventory_image = minetest.inventorycube("steel_block.png"),
|
||||
is_ground_content = true,
|
||||
material = digprop_stonelike(5.0),
|
||||
})
|
||||
|
||||
minetest.register_node("nyancat", {
|
||||
minetest.register_node(":nyancat", {
|
||||
tile_images = {"nc_side.png", "nc_side.png", "nc_side.png",
|
||||
"nc_side.png", "nc_back.png", "nc_front.png"},
|
||||
inventory_image = "nc_front.png",
|
||||
@@ -1221,14 +1250,14 @@ minetest.register_node("nyancat", {
|
||||
furnace_burntime = 1,
|
||||
})
|
||||
|
||||
minetest.register_node("nyancat_rainbow", {
|
||||
minetest.register_node(":nyancat_rainbow", {
|
||||
tile_images = {"nc_rb.png"},
|
||||
inventory_image = "nc_rb.png",
|
||||
material = digprop_stonelike(3.0),
|
||||
furnace_burntime = 1,
|
||||
})
|
||||
|
||||
minetest.register_node("sapling", {
|
||||
minetest.register_node(":sapling", {
|
||||
drawtype = "plantlike",
|
||||
visual_scale = 1.0,
|
||||
tile_images = {"sapling.png"},
|
||||
@@ -1240,7 +1269,7 @@ minetest.register_node("sapling", {
|
||||
furnace_burntime = 10,
|
||||
})
|
||||
|
||||
minetest.register_node("apple", {
|
||||
minetest.register_node(":apple", {
|
||||
drawtype = "plantlike",
|
||||
visual_scale = 1.0,
|
||||
tile_images = {"apple.png"},
|
||||
@@ -1258,51 +1287,51 @@ minetest.register_node("apple", {
|
||||
-- Crafting items
|
||||
--
|
||||
|
||||
minetest.register_craftitem("Stick", {
|
||||
minetest.register_craftitem(":Stick", {
|
||||
image = "stick.png",
|
||||
--furnace_burntime = ...,
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("paper", {
|
||||
minetest.register_craftitem(":paper", {
|
||||
image = "paper.png",
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("book", {
|
||||
minetest.register_craftitem(":book", {
|
||||
image = "book.png",
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("lump_of_coal", {
|
||||
minetest.register_craftitem(":lump_of_coal", {
|
||||
image = "lump_of_coal.png",
|
||||
furnace_burntime = 40;
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("lump_of_iron", {
|
||||
minetest.register_craftitem(":lump_of_iron", {
|
||||
image = "lump_of_iron.png",
|
||||
cookresult_item = 'craft "steel_ingot" 1',
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("lump_of_clay", {
|
||||
minetest.register_craftitem(":lump_of_clay", {
|
||||
image = "lump_of_clay.png",
|
||||
cookresult_item = 'craft "clay_brick" 1',
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("steel_ingot", {
|
||||
minetest.register_craftitem(":steel_ingot", {
|
||||
image = "steel_ingot.png",
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("clay_brick", {
|
||||
minetest.register_craftitem(":clay_brick", {
|
||||
image = "clay_brick.png",
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("rat", {
|
||||
minetest.register_craftitem(":rat", {
|
||||
image = "rat.png",
|
||||
cookresult_item = 'craft "cooked_rat" 1',
|
||||
on_drop = function(item, dropper, pos)
|
||||
@@ -1311,19 +1340,19 @@ minetest.register_craftitem("rat", {
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("cooked_rat", {
|
||||
minetest.register_craftitem(":cooked_rat", {
|
||||
image = "cooked_rat.png",
|
||||
cookresult_item = 'craft "scorched_stuff" 1',
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
on_use = minetest.craftitem_eat(6),
|
||||
})
|
||||
|
||||
minetest.register_craftitem("scorched_stuff", {
|
||||
minetest.register_craftitem(":scorched_stuff", {
|
||||
image = "scorched_stuff.png",
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("firefly", {
|
||||
minetest.register_craftitem(":firefly", {
|
||||
image = "firefly.png",
|
||||
on_drop = function(item, dropper, pos)
|
||||
minetest.env:add_firefly(pos)
|
||||
@@ -1331,13 +1360,13 @@ minetest.register_craftitem("firefly", {
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("apple", {
|
||||
minetest.register_craftitem(":apple", {
|
||||
image = "apple.png",
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
on_use = minetest.craftitem_eat(4),
|
||||
})
|
||||
|
||||
minetest.register_craftitem("apple_iron", {
|
||||
minetest.register_craftitem(":apple_iron", {
|
||||
image = "apple_iron.png",
|
||||
on_place_on_ground = minetest.craftitem_place_item,
|
||||
on_use = minetest.craftitem_eat(8),
|
||||
@@ -1389,7 +1418,7 @@ function nodeupdate_single(p)
|
||||
n_bottom = minetest.env:get_node(p_bottom)
|
||||
if n_bottom.name == "air" then
|
||||
minetest.env:remove_node(p)
|
||||
minetest.env:add_luaentity(p, "falling_"..n.name)
|
||||
minetest.env:add_luaentity(p, "default:falling_"..n.name)
|
||||
nodeupdate(p)
|
||||
end
|
||||
end
|
||||
@@ -1411,7 +1440,7 @@ end
|
||||
--
|
||||
|
||||
function register_falling_node(nodename, texture)
|
||||
minetest.register_entity("falling_"..nodename, {
|
||||
minetest.register_entity("default:falling_"..nodename, {
|
||||
-- Static definition
|
||||
physical = true,
|
||||
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
|
||||
@@ -1452,31 +1481,23 @@ end
|
||||
minetest.register_globalstep(on_step)
|
||||
|
||||
function on_placenode(p, node)
|
||||
print("on_placenode")
|
||||
--print("on_placenode")
|
||||
nodeupdate(p)
|
||||
end
|
||||
minetest.register_on_placenode(on_placenode)
|
||||
|
||||
function on_dignode(p, node)
|
||||
print("on_dignode")
|
||||
--print("on_dignode")
|
||||
nodeupdate(p)
|
||||
end
|
||||
minetest.register_on_dignode(on_dignode)
|
||||
|
||||
function on_punchnode(p, node)
|
||||
print("on_punchnode")
|
||||
if node.name == "TNT" then
|
||||
minetest.env:remove_node(p)
|
||||
minetest.env:add_luaentity(p, "TNT")
|
||||
--minetest.env:add_luaentity(p, "testentity")
|
||||
--minetest.env:add_firefly(p)
|
||||
nodeupdate(p)
|
||||
end
|
||||
end
|
||||
minetest.register_on_punchnode(on_punchnode)
|
||||
|
||||
minetest.register_on_chat_message(function(name, message)
|
||||
print("default on_chat_message: name="..dump(name).." message="..dump(message))
|
||||
--print("default on_chat_message: name="..dump(name).." message="..dump(message))
|
||||
local cmd = "/giveme"
|
||||
if message:sub(0, #cmd) == cmd then
|
||||
if not minetest.get_player_privs(name)["give"] then
|
||||
@@ -1506,8 +1527,6 @@ minetest.register_on_chat_message(function(name, message)
|
||||
end
|
||||
local cmd = "/give"
|
||||
if message:sub(0, #cmd) == cmd then
|
||||
print("minetest.get_player_privs(name)="
|
||||
..dump(minetest.get_player_privs(name)))
|
||||
if not minetest.get_player_privs(name)["give"] then
|
||||
minetest.chat_send_player(name, "you don't have permission to give")
|
||||
return true -- Handled chat message
|
||||
|
||||
BIN
data/mods/default/textures/wieldhand.png
Normal file
BIN
data/mods/default/textures/wieldhand.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 384 B |
@@ -4,18 +4,18 @@
|
||||
|
||||
-- An example furnace-thing implemented in Lua
|
||||
|
||||
minetest.register_node("luafurnace", {
|
||||
minetest.register_node("experimental:luafurnace", {
|
||||
tile_images = {"lava.png", "furnace_side.png", "furnace_side.png",
|
||||
"furnace_side.png", "furnace_side.png", "furnace_front.png"},
|
||||
--inventory_image = "furnace_front.png",
|
||||
inventory_image = inventorycube("furnace_front.png"),
|
||||
inventory_image = minetest.inventorycube("furnace_front.png"),
|
||||
paramtype = "facedir_simple",
|
||||
metadata_name = "generic",
|
||||
material = digprop_stonelike(3.0),
|
||||
})
|
||||
|
||||
minetest.register_on_placenode(function(pos, newnode, placer)
|
||||
if newnode.name == "luafurnace" then
|
||||
if newnode.name == "experimental:luafurnace" then
|
||||
print("get_meta");
|
||||
local meta = minetest.env:get_meta(pos)
|
||||
print("inventory_set_list");
|
||||
@@ -42,7 +42,7 @@ minetest.register_on_placenode(function(pos, newnode, placer)
|
||||
end)
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"luafurnace"},
|
||||
nodenames = {"experimental:luafurnace"},
|
||||
interval = 1.0,
|
||||
chance = 1,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
@@ -97,7 +97,7 @@ minetest.register_abm({
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'node "luafurnace" 1',
|
||||
output = 'node "experimental:luafurnace" 1',
|
||||
recipe = {
|
||||
{'node "cobble"', 'node "cobble"', 'node "cobble"'},
|
||||
{'node "cobble"', 'node "cobble"', 'node "cobble"'},
|
||||
@@ -132,9 +132,10 @@ minetest.register_craft({
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_node("somenode", {
|
||||
minetest.register_node("experimental:somenode", {
|
||||
tile_images = {"lava.png", "mese.png", "stone.png", "grass.png", "cobble.png", "tree_top.png"},
|
||||
inventory_image = "treeprop.png",
|
||||
inventory_image = minetest.inventorycube("lava.png", "mese.png", "stone.png"),
|
||||
--inventory_image = "treeprop.png",
|
||||
material = {
|
||||
diggability = "normal",
|
||||
weight = 0,
|
||||
@@ -151,7 +152,7 @@ minetest.register_node("somenode", {
|
||||
--
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'node "TNT" 4',
|
||||
output = 'node "experimental:tnt" 4',
|
||||
recipe = {
|
||||
{'node "wood" 1'},
|
||||
{'craft "lump_of_coal" 1'},
|
||||
@@ -159,7 +160,7 @@ minetest.register_craft({
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_node("TNT", {
|
||||
minetest.register_node("experimental:tnt", {
|
||||
tile_images = {"tnt_top.png", "tnt_bottom.png", "tnt_side.png", "tnt_side.png", "tnt_side.png", "tnt_side.png"},
|
||||
inventory_image = "tnt_side.png",
|
||||
dug_item = '', -- Get nothing
|
||||
@@ -168,6 +169,14 @@ minetest.register_node("TNT", {
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_on_punchnode(function(p, node)
|
||||
if node.name == "experimental:tnt" then
|
||||
minetest.env:remove_node(p)
|
||||
minetest.env:add_luaentity(p, "experimental:tnt")
|
||||
nodeupdate(p)
|
||||
end
|
||||
end)
|
||||
|
||||
local TNT = {
|
||||
-- Static definition
|
||||
physical = true, -- Collides with things
|
||||
@@ -225,16 +234,15 @@ function TNT:on_rightclick(clicker)
|
||||
--self.object:moveto(pos, false)
|
||||
end
|
||||
|
||||
print("TNT dump: "..dump(TNT))
|
||||
|
||||
print("Registering TNT");
|
||||
minetest.register_entity("TNT", TNT)
|
||||
--print("TNT dump: "..dump(TNT))
|
||||
--print("Registering TNT");
|
||||
minetest.register_entity("experimental:tnt", TNT)
|
||||
|
||||
--
|
||||
-- A test entity for testing animated and yaw-modulated sprites
|
||||
--
|
||||
|
||||
minetest.register_entity("testentity", {
|
||||
minetest.register_entity("experimental:testentity", {
|
||||
-- Static definition
|
||||
physical = true, -- Collides with things
|
||||
-- weight = 5,
|
||||
|
||||
@@ -94,6 +94,7 @@ configure_file(
|
||||
)
|
||||
|
||||
set(common_SRCS
|
||||
mods.cpp
|
||||
serverremoteplayer.cpp
|
||||
content_abm.cpp
|
||||
craftdef.cpp
|
||||
@@ -160,6 +161,7 @@ set(minetest_SRCS
|
||||
MyBillboardSceneNode.cpp
|
||||
content_mapblock.cpp
|
||||
content_cao.cpp
|
||||
mesh.cpp
|
||||
mapblock_mesh.cpp
|
||||
farmesh.cpp
|
||||
keycode.cpp
|
||||
|
||||
297
src/camera.cpp
297
src/camera.cpp
@@ -22,21 +22,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "client.h"
|
||||
#include "main.h" // for g_settings
|
||||
#include "map.h"
|
||||
#include "mesh.h"
|
||||
#include "player.h"
|
||||
#include "tile.h"
|
||||
#include <cmath>
|
||||
#include <SAnimatedMesh.h>
|
||||
#include "settings.h"
|
||||
#include "nodedef.h" // For wield visualization
|
||||
|
||||
// In Irrlicht 1.8 the signature of ITexture::lock was changed from
|
||||
// (bool, u32) to (E_TEXTURE_LOCK_MODE, u32).
|
||||
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
|
||||
#define MY_ETLM_READ_ONLY true
|
||||
#else
|
||||
#define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY
|
||||
#endif
|
||||
|
||||
Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
|
||||
m_smgr(smgr),
|
||||
m_playernode(NULL),
|
||||
@@ -277,7 +269,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize)
|
||||
|
||||
// Position the wielded item
|
||||
v3f wield_position = v3f(45, -35, 65);
|
||||
v3f wield_rotation = v3f(-100, 110, -100);
|
||||
v3f wield_rotation = v3f(-100, 120, -100);
|
||||
if (m_digging_button != -1)
|
||||
{
|
||||
f32 digfrac = m_digging_anim;
|
||||
@@ -480,7 +472,6 @@ void Camera::wield(const InventoryItem* item, IGameDef *gamedef)
|
||||
case NDT_ALLFACES:
|
||||
case NDT_ALLFACES_OPTIONAL:
|
||||
m_wieldnode->setCube(ndef->get(content).tiles);
|
||||
m_wieldnode->setScale(v3f(30));
|
||||
isCube = true;
|
||||
break;
|
||||
default:
|
||||
@@ -492,7 +483,6 @@ void Camera::wield(const InventoryItem* item, IGameDef *gamedef)
|
||||
if (!isCube)
|
||||
{
|
||||
m_wieldnode->setSprite(item->getImageRaw());
|
||||
m_wieldnode->setScale(v3f(40));
|
||||
}
|
||||
|
||||
m_wieldnode->setVisible(true);
|
||||
@@ -500,7 +490,8 @@ void Camera::wield(const InventoryItem* item, IGameDef *gamedef)
|
||||
else
|
||||
{
|
||||
// Bare hands
|
||||
m_wieldnode->setVisible(false);
|
||||
m_wieldnode->setSprite(gamedef->tsrc()->getTextureRaw("wieldhand.png"));
|
||||
m_wieldnode->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,7 +525,6 @@ ExtrudedSpriteSceneNode::ExtrudedSpriteSceneNode(
|
||||
ISceneNode(parent, mgr, id, position, rotation, scale)
|
||||
{
|
||||
m_meshnode = mgr->addMeshSceneNode(NULL, this, -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true);
|
||||
m_thickness = 0.1;
|
||||
m_cubemesh = NULL;
|
||||
m_is_cube = false;
|
||||
m_light = LIGHT_MAX;
|
||||
@@ -549,6 +539,8 @@ ExtrudedSpriteSceneNode::~ExtrudedSpriteSceneNode()
|
||||
|
||||
void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture)
|
||||
{
|
||||
const v3f sprite_scale(40.0, 40.0, 4.0); // width, height, thickness
|
||||
|
||||
if (texture == NULL)
|
||||
{
|
||||
m_meshnode->setVisible(false);
|
||||
@@ -566,7 +558,9 @@ void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture)
|
||||
else
|
||||
{
|
||||
// Texture was not yet extruded, do it now and save in cache
|
||||
mesh = extrude(texture);
|
||||
mesh = createExtrudedMesh(texture,
|
||||
SceneManager->getVideoDriver(),
|
||||
sprite_scale);
|
||||
if (mesh == NULL)
|
||||
{
|
||||
dstream << "Warning: failed to extrude sprite" << std::endl;
|
||||
@@ -578,7 +572,6 @@ void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture)
|
||||
mesh->drop();
|
||||
}
|
||||
|
||||
m_meshnode->setScale(v3f(1, 1, m_thickness));
|
||||
m_meshnode->getMaterial(0).setTexture(0, texture);
|
||||
m_meshnode->getMaterial(0).setFlag(video::EMF_LIGHTING, false);
|
||||
m_meshnode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
@@ -590,11 +583,14 @@ void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture)
|
||||
|
||||
void ExtrudedSpriteSceneNode::setCube(const TileSpec tiles[6])
|
||||
{
|
||||
const v3f cube_scale(30.0, 30.0, 30.0);
|
||||
|
||||
if (m_cubemesh == NULL)
|
||||
m_cubemesh = createCubeMesh();
|
||||
{
|
||||
m_cubemesh = createCubeMesh(cube_scale);
|
||||
}
|
||||
|
||||
m_meshnode->setMesh(m_cubemesh);
|
||||
m_meshnode->setScale(v3f(1));
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
// Get the tile texture and atlas transformation
|
||||
@@ -624,7 +620,7 @@ void ExtrudedSpriteSceneNode::updateLight(u8 light)
|
||||
// Set brightness one lower than incoming light
|
||||
diminish_light(li);
|
||||
video::SColor color(255,li,li,li);
|
||||
setMeshVerticesColor(m_meshnode->getMesh(), color);
|
||||
setMeshColor(m_meshnode->getMesh(), color);
|
||||
}
|
||||
|
||||
void ExtrudedSpriteSceneNode::removeSpriteFromCache(video::ITexture* texture)
|
||||
@@ -635,13 +631,6 @@ void ExtrudedSpriteSceneNode::removeSpriteFromCache(video::ITexture* texture)
|
||||
cache->removeMesh(mesh);
|
||||
}
|
||||
|
||||
void ExtrudedSpriteSceneNode::setSpriteThickness(f32 thickness)
|
||||
{
|
||||
m_thickness = thickness;
|
||||
if (!m_is_cube)
|
||||
m_meshnode->setScale(v3f(1, 1, thickness));
|
||||
}
|
||||
|
||||
const core::aabbox3d<f32>& ExtrudedSpriteSceneNode::getBoundingBox() const
|
||||
{
|
||||
return m_meshnode->getBoundingBox();
|
||||
@@ -665,259 +654,3 @@ io::path ExtrudedSpriteSceneNode::getExtrudedName(video::ITexture* texture)
|
||||
path.append("/[extruded]");
|
||||
return path;
|
||||
}
|
||||
|
||||
scene::IAnimatedMesh* ExtrudedSpriteSceneNode::extrudeARGB(u32 width, u32 height, u8* data)
|
||||
{
|
||||
const s32 argb_wstep = 4 * width;
|
||||
const s32 alpha_threshold = 1;
|
||||
|
||||
scene::IMeshBuffer* buf = new scene::SMeshBuffer();
|
||||
video::SColor c(255,255,255,255);
|
||||
|
||||
// Front and back
|
||||
{
|
||||
video::S3DVertex vertices[8] =
|
||||
{
|
||||
video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
|
||||
video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
|
||||
video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
|
||||
video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
|
||||
video::S3DVertex(+0.5,-0.5,+0.5, 0,0,+1, c, 1,1),
|
||||
video::S3DVertex(+0.5,+0.5,+0.5, 0,0,+1, c, 1,0),
|
||||
video::S3DVertex(-0.5,+0.5,+0.5, 0,0,+1, c, 0,0),
|
||||
video::S3DVertex(-0.5,-0.5,+0.5, 0,0,+1, c, 0,1),
|
||||
};
|
||||
u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
|
||||
buf->append(vertices, 8, indices, 12);
|
||||
}
|
||||
|
||||
// "Interior"
|
||||
// (add faces where a solid pixel is next to a transparent one)
|
||||
u8* solidity = new u8[(width+2) * (height+2)];
|
||||
u32 wstep = width + 2;
|
||||
for (u32 y = 0; y < height + 2; ++y)
|
||||
{
|
||||
u8* scanline = solidity + y * wstep;
|
||||
if (y == 0 || y == height + 1)
|
||||
{
|
||||
for (u32 x = 0; x < width + 2; ++x)
|
||||
scanline[x] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
scanline[0] = 0;
|
||||
u8* argb_scanline = data + (y - 1) * argb_wstep;
|
||||
for (u32 x = 0; x < width; ++x)
|
||||
scanline[x+1] = (argb_scanline[x*4+3] >= alpha_threshold);
|
||||
scanline[width + 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// without this, there would be occasional "holes" in the mesh
|
||||
f32 eps = 0.01;
|
||||
|
||||
for (u32 y = 0; y <= height; ++y)
|
||||
{
|
||||
u8* scanline = solidity + y * wstep + 1;
|
||||
for (u32 x = 0; x <= width; ++x)
|
||||
{
|
||||
if (scanline[x] && !scanline[x + wstep])
|
||||
{
|
||||
u32 xx = x + 1;
|
||||
while (scanline[xx] && !scanline[xx + wstep])
|
||||
++xx;
|
||||
f32 vx1 = (x - eps) / (f32) width - 0.5;
|
||||
f32 vx2 = (xx + eps) / (f32) width - 0.5;
|
||||
f32 vy = 0.5 - (y - eps) / (f32) height;
|
||||
f32 tx1 = x / (f32) width;
|
||||
f32 tx2 = xx / (f32) width;
|
||||
f32 ty = (y - 0.5) / (f32) height;
|
||||
video::S3DVertex vertices[8] =
|
||||
{
|
||||
video::S3DVertex(vx1,vy,-0.5, 0,-1,0, c, tx1,ty),
|
||||
video::S3DVertex(vx2,vy,-0.5, 0,-1,0, c, tx2,ty),
|
||||
video::S3DVertex(vx2,vy,+0.5, 0,-1,0, c, tx2,ty),
|
||||
video::S3DVertex(vx1,vy,+0.5, 0,-1,0, c, tx1,ty),
|
||||
};
|
||||
u16 indices[6] = {0,1,2,2,3,0};
|
||||
buf->append(vertices, 4, indices, 6);
|
||||
x = xx - 1;
|
||||
}
|
||||
if (!scanline[x] && scanline[x + wstep])
|
||||
{
|
||||
u32 xx = x + 1;
|
||||
while (!scanline[xx] && scanline[xx + wstep])
|
||||
++xx;
|
||||
f32 vx1 = (x - eps) / (f32) width - 0.5;
|
||||
f32 vx2 = (xx + eps) / (f32) width - 0.5;
|
||||
f32 vy = 0.5 - (y + eps) / (f32) height;
|
||||
f32 tx1 = x / (f32) width;
|
||||
f32 tx2 = xx / (f32) width;
|
||||
f32 ty = (y + 0.5) / (f32) height;
|
||||
video::S3DVertex vertices[8] =
|
||||
{
|
||||
video::S3DVertex(vx1,vy,-0.5, 0,1,0, c, tx1,ty),
|
||||
video::S3DVertex(vx1,vy,+0.5, 0,1,0, c, tx1,ty),
|
||||
video::S3DVertex(vx2,vy,+0.5, 0,1,0, c, tx2,ty),
|
||||
video::S3DVertex(vx2,vy,-0.5, 0,1,0, c, tx2,ty),
|
||||
};
|
||||
u16 indices[6] = {0,1,2,2,3,0};
|
||||
buf->append(vertices, 4, indices, 6);
|
||||
x = xx - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 x = 0; x <= width; ++x)
|
||||
{
|
||||
u8* scancol = solidity + x + wstep;
|
||||
for (u32 y = 0; y <= height; ++y)
|
||||
{
|
||||
if (scancol[y * wstep] && !scancol[y * wstep + 1])
|
||||
{
|
||||
u32 yy = y + 1;
|
||||
while (scancol[yy * wstep] && !scancol[yy * wstep + 1])
|
||||
++yy;
|
||||
f32 vx = (x - eps) / (f32) width - 0.5;
|
||||
f32 vy1 = 0.5 - (y - eps) / (f32) height;
|
||||
f32 vy2 = 0.5 - (yy + eps) / (f32) height;
|
||||
f32 tx = (x - 0.5) / (f32) width;
|
||||
f32 ty1 = y / (f32) height;
|
||||
f32 ty2 = yy / (f32) height;
|
||||
video::S3DVertex vertices[8] =
|
||||
{
|
||||
video::S3DVertex(vx,vy1,-0.5, 1,0,0, c, tx,ty1),
|
||||
video::S3DVertex(vx,vy1,+0.5, 1,0,0, c, tx,ty1),
|
||||
video::S3DVertex(vx,vy2,+0.5, 1,0,0, c, tx,ty2),
|
||||
video::S3DVertex(vx,vy2,-0.5, 1,0,0, c, tx,ty2),
|
||||
};
|
||||
u16 indices[6] = {0,1,2,2,3,0};
|
||||
buf->append(vertices, 4, indices, 6);
|
||||
y = yy - 1;
|
||||
}
|
||||
if (!scancol[y * wstep] && scancol[y * wstep + 1])
|
||||
{
|
||||
u32 yy = y + 1;
|
||||
while (!scancol[yy * wstep] && scancol[yy * wstep + 1])
|
||||
++yy;
|
||||
f32 vx = (x + eps) / (f32) width - 0.5;
|
||||
f32 vy1 = 0.5 - (y - eps) / (f32) height;
|
||||
f32 vy2 = 0.5 - (yy + eps) / (f32) height;
|
||||
f32 tx = (x + 0.5) / (f32) width;
|
||||
f32 ty1 = y / (f32) height;
|
||||
f32 ty2 = yy / (f32) height;
|
||||
video::S3DVertex vertices[8] =
|
||||
{
|
||||
video::S3DVertex(vx,vy1,-0.5, -1,0,0, c, tx,ty1),
|
||||
video::S3DVertex(vx,vy2,-0.5, -1,0,0, c, tx,ty2),
|
||||
video::S3DVertex(vx,vy2,+0.5, -1,0,0, c, tx,ty2),
|
||||
video::S3DVertex(vx,vy1,+0.5, -1,0,0, c, tx,ty1),
|
||||
};
|
||||
u16 indices[6] = {0,1,2,2,3,0};
|
||||
buf->append(vertices, 4, indices, 6);
|
||||
y = yy - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add to mesh
|
||||
scene::SMesh* mesh = new scene::SMesh();
|
||||
buf->recalculateBoundingBox();
|
||||
mesh->addMeshBuffer(buf);
|
||||
buf->drop();
|
||||
mesh->recalculateBoundingBox();
|
||||
scene::SAnimatedMesh* anim_mesh = new scene::SAnimatedMesh(mesh);
|
||||
mesh->drop();
|
||||
return anim_mesh;
|
||||
}
|
||||
|
||||
scene::IAnimatedMesh* ExtrudedSpriteSceneNode::extrude(video::ITexture* texture)
|
||||
{
|
||||
scene::IAnimatedMesh* mesh = NULL;
|
||||
core::dimension2d<u32> size = texture->getSize();
|
||||
video::ECOLOR_FORMAT format = texture->getColorFormat();
|
||||
if (format == video::ECF_A8R8G8B8)
|
||||
{
|
||||
// Texture is in the correct color format, we can pass it
|
||||
// to extrudeARGB right away.
|
||||
void* data = texture->lock(MY_ETLM_READ_ONLY);
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
mesh = extrudeARGB(size.Width, size.Height, (u8*) data);
|
||||
texture->unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
||||
|
||||
video::IImage* img1 = driver->createImageFromData(format, size, texture->lock(MY_ETLM_READ_ONLY));
|
||||
if (img1 == NULL)
|
||||
return NULL;
|
||||
|
||||
// img1 is in the texture's color format, convert to 8-bit ARGB
|
||||
video::IImage* img2 = driver->createImage(video::ECF_A8R8G8B8, size);
|
||||
if (img2 != NULL)
|
||||
{
|
||||
img1->copyTo(img2);
|
||||
img1->drop();
|
||||
|
||||
mesh = extrudeARGB(size.Width, size.Height, (u8*) img2->lock());
|
||||
img2->unlock();
|
||||
img2->drop();
|
||||
}
|
||||
img1->drop();
|
||||
}
|
||||
return mesh;
|
||||
}
|
||||
|
||||
scene::IMesh* ExtrudedSpriteSceneNode::createCubeMesh()
|
||||
{
|
||||
video::SColor c(255,255,255,255);
|
||||
video::S3DVertex vertices[24] =
|
||||
{
|
||||
// Up
|
||||
video::S3DVertex(-0.5,+0.5,-0.5, 0,1,0, c, 0,1),
|
||||
video::S3DVertex(-0.5,+0.5,+0.5, 0,1,0, c, 0,0),
|
||||
video::S3DVertex(+0.5,+0.5,+0.5, 0,1,0, c, 1,0),
|
||||
video::S3DVertex(+0.5,+0.5,-0.5, 0,1,0, c, 1,1),
|
||||
// Down
|
||||
video::S3DVertex(-0.5,-0.5,-0.5, 0,-1,0, c, 0,0),
|
||||
video::S3DVertex(+0.5,-0.5,-0.5, 0,-1,0, c, 1,0),
|
||||
video::S3DVertex(+0.5,-0.5,+0.5, 0,-1,0, c, 1,1),
|
||||
video::S3DVertex(-0.5,-0.5,+0.5, 0,-1,0, c, 0,1),
|
||||
// Right
|
||||
video::S3DVertex(+0.5,-0.5,-0.5, 1,0,0, c, 0,1),
|
||||
video::S3DVertex(+0.5,+0.5,-0.5, 1,0,0, c, 0,0),
|
||||
video::S3DVertex(+0.5,+0.5,+0.5, 1,0,0, c, 1,0),
|
||||
video::S3DVertex(+0.5,-0.5,+0.5, 1,0,0, c, 1,1),
|
||||
// Left
|
||||
video::S3DVertex(-0.5,-0.5,-0.5, -1,0,0, c, 1,1),
|
||||
video::S3DVertex(-0.5,-0.5,+0.5, -1,0,0, c, 0,1),
|
||||
video::S3DVertex(-0.5,+0.5,+0.5, -1,0,0, c, 0,0),
|
||||
video::S3DVertex(-0.5,+0.5,-0.5, -1,0,0, c, 1,0),
|
||||
// Back
|
||||
video::S3DVertex(-0.5,-0.5,+0.5, 0,0,1, c, 1,1),
|
||||
video::S3DVertex(+0.5,-0.5,+0.5, 0,0,1, c, 0,1),
|
||||
video::S3DVertex(+0.5,+0.5,+0.5, 0,0,1, c, 0,0),
|
||||
video::S3DVertex(-0.5,+0.5,+0.5, 0,0,1, c, 1,0),
|
||||
// Front
|
||||
video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
|
||||
video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
|
||||
video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
|
||||
video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
|
||||
};
|
||||
|
||||
u16 indices[6] = {0,1,2,2,3,0};
|
||||
|
||||
scene::SMesh* mesh = new scene::SMesh();
|
||||
for (u32 i=0; i<6; ++i)
|
||||
{
|
||||
scene::IMeshBuffer* buf = new scene::SMeshBuffer();
|
||||
buf->append(vertices + 4 * i, 4, indices, 6);
|
||||
buf->recalculateBoundingBox();
|
||||
mesh->addMeshBuffer(buf);
|
||||
buf->drop();
|
||||
}
|
||||
mesh->recalculateBoundingBox();
|
||||
return mesh;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "inventory.h"
|
||||
#include "mesh.h"
|
||||
#include "tile.h"
|
||||
#include "utility.h"
|
||||
#include <ICameraSceneNode.h>
|
||||
@@ -206,9 +207,6 @@ class ExtrudedSpriteSceneNode: public scene::ISceneNode
|
||||
void setSprite(video::ITexture* texture);
|
||||
void setCube(const TileSpec tiles[6]);
|
||||
|
||||
f32 getSpriteThickness() const { return m_thickness; }
|
||||
void setSpriteThickness(f32 thickness);
|
||||
|
||||
void updateLight(u8 light);
|
||||
|
||||
void removeSpriteFromCache(video::ITexture* texture);
|
||||
@@ -219,16 +217,11 @@ class ExtrudedSpriteSceneNode: public scene::ISceneNode
|
||||
|
||||
private:
|
||||
scene::IMeshSceneNode* m_meshnode;
|
||||
f32 m_thickness;
|
||||
scene::IMesh* m_cubemesh;
|
||||
bool m_is_cube;
|
||||
u8 m_light;
|
||||
|
||||
// internal extrusion helper methods
|
||||
io::path getExtrudedName(video::ITexture* texture);
|
||||
scene::IAnimatedMesh* extrudeARGB(u32 width, u32 height, u8* data);
|
||||
scene::IAnimatedMesh* extrude(video::ITexture* texture);
|
||||
scene::IMesh* createCubeMesh();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "gamedef.h"
|
||||
#include "clientobject.h"
|
||||
#include "content_object.h"
|
||||
#include "mesh.h"
|
||||
#include "utility.h" // For IntervalLimiter
|
||||
class Settings;
|
||||
#include "MyBillboardSceneNode.h"
|
||||
@@ -630,7 +631,7 @@ void ItemCAO::updateLight(u8 light_at_pos)
|
||||
|
||||
u8 li = decode_light(light_at_pos);
|
||||
video::SColor color(255,li,li,li);
|
||||
setMeshVerticesColor(m_node->getMesh(), color);
|
||||
setMeshColor(m_node->getMesh(), color);
|
||||
}
|
||||
|
||||
v3s16 ItemCAO::getLightPosition()
|
||||
@@ -778,7 +779,7 @@ void RatCAO::updateLight(u8 light_at_pos)
|
||||
|
||||
u8 li = decode_light(light_at_pos);
|
||||
video::SColor color(255,li,li,li);
|
||||
setMeshVerticesColor(m_node->getMesh(), color);
|
||||
setMeshColor(m_node->getMesh(), color);
|
||||
}
|
||||
|
||||
v3s16 RatCAO::getLightPosition()
|
||||
@@ -934,7 +935,7 @@ void Oerkki1CAO::updateLight(u8 light_at_pos)
|
||||
|
||||
u8 li = decode_light(light_at_pos);
|
||||
video::SColor color(255,li,li,li);
|
||||
setMeshVerticesColor(m_node->getMesh(), color);
|
||||
setMeshColor(m_node->getMesh(), color);
|
||||
}
|
||||
|
||||
v3s16 Oerkki1CAO::getLightPosition()
|
||||
@@ -1165,7 +1166,7 @@ void FireflyCAO::updateLight(u8 light_at_pos)
|
||||
|
||||
u8 li = 255;
|
||||
video::SColor color(255,li,li,li);
|
||||
setMeshVerticesColor(m_node->getMesh(), color);
|
||||
setMeshColor(m_node->getMesh(), color);
|
||||
}
|
||||
|
||||
v3s16 FireflyCAO::getLightPosition()
|
||||
@@ -1866,7 +1867,7 @@ class LuaEntityCAO : public ClientActiveObject
|
||||
u8 li = decode_light(light_at_pos);
|
||||
video::SColor color(255,li,li,li);
|
||||
if(m_meshnode){
|
||||
setMeshVerticesColor(m_meshnode->getMesh(), color);
|
||||
setMeshColor(m_meshnode->getMesh(), color);
|
||||
m_meshnode->setVisible(true);
|
||||
}
|
||||
if(m_spritenode){
|
||||
@@ -2250,7 +2251,7 @@ class PlayerCAO : public ClientActiveObject
|
||||
|
||||
u8 li = decode_light(light_at_pos);
|
||||
video::SColor color(255,li,li,li);
|
||||
setMeshVerticesColor(m_node->getMesh(), color);
|
||||
setMeshColor(m_node->getMesh(), color);
|
||||
}
|
||||
|
||||
v3s16 getLightPosition()
|
||||
|
||||
@@ -429,6 +429,7 @@ Doing currently:
|
||||
#include "settings.h"
|
||||
#include "profiler.h"
|
||||
#include "log.h"
|
||||
#include "mods.h"
|
||||
|
||||
/*
|
||||
Settings.
|
||||
@@ -1630,7 +1631,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// Break out of menu-game loop to shut down cleanly
|
||||
if(device->run() == false)
|
||||
if(device->run() == false || kill == true)
|
||||
break;
|
||||
|
||||
/*
|
||||
@@ -1662,6 +1663,11 @@ int main(int argc, char *argv[])
|
||||
errorstream<<"Socket error (port already in use?)"<<std::endl;
|
||||
error_message = L"Socket error (port already in use?)";
|
||||
}
|
||||
catch(ModError &e)
|
||||
{
|
||||
errorstream<<e.what()<<std::endl;
|
||||
error_message = narrow_to_wide(e.what()) + L"\nCheck debug.txt for details.";
|
||||
}
|
||||
#ifdef NDEBUG
|
||||
catch(std::exception &e)
|
||||
{
|
||||
|
||||
362
src/mesh.cpp
Normal file
362
src/mesh.cpp
Normal file
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "mesh.h"
|
||||
#include <IAnimatedMesh.h>
|
||||
#include <SAnimatedMesh.h>
|
||||
|
||||
// In Irrlicht 1.8 the signature of ITexture::lock was changed from
|
||||
// (bool, u32) to (E_TEXTURE_LOCK_MODE, u32).
|
||||
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
|
||||
#define MY_ETLM_READ_ONLY true
|
||||
#else
|
||||
#define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY
|
||||
#endif
|
||||
|
||||
scene::IAnimatedMesh* createCubeMesh(v3f scale)
|
||||
{
|
||||
video::SColor c(255,255,255,255);
|
||||
video::S3DVertex vertices[24] =
|
||||
{
|
||||
// Up
|
||||
video::S3DVertex(-0.5,+0.5,-0.5, 0,1,0, c, 0,1),
|
||||
video::S3DVertex(-0.5,+0.5,+0.5, 0,1,0, c, 0,0),
|
||||
video::S3DVertex(+0.5,+0.5,+0.5, 0,1,0, c, 1,0),
|
||||
video::S3DVertex(+0.5,+0.5,-0.5, 0,1,0, c, 1,1),
|
||||
// Down
|
||||
video::S3DVertex(-0.5,-0.5,-0.5, 0,-1,0, c, 0,0),
|
||||
video::S3DVertex(+0.5,-0.5,-0.5, 0,-1,0, c, 1,0),
|
||||
video::S3DVertex(+0.5,-0.5,+0.5, 0,-1,0, c, 1,1),
|
||||
video::S3DVertex(-0.5,-0.5,+0.5, 0,-1,0, c, 0,1),
|
||||
// Right
|
||||
video::S3DVertex(+0.5,-0.5,-0.5, 1,0,0, c, 0,1),
|
||||
video::S3DVertex(+0.5,+0.5,-0.5, 1,0,0, c, 0,0),
|
||||
video::S3DVertex(+0.5,+0.5,+0.5, 1,0,0, c, 1,0),
|
||||
video::S3DVertex(+0.5,-0.5,+0.5, 1,0,0, c, 1,1),
|
||||
// Left
|
||||
video::S3DVertex(-0.5,-0.5,-0.5, -1,0,0, c, 1,1),
|
||||
video::S3DVertex(-0.5,-0.5,+0.5, -1,0,0, c, 0,1),
|
||||
video::S3DVertex(-0.5,+0.5,+0.5, -1,0,0, c, 0,0),
|
||||
video::S3DVertex(-0.5,+0.5,-0.5, -1,0,0, c, 1,0),
|
||||
// Back
|
||||
video::S3DVertex(-0.5,-0.5,+0.5, 0,0,1, c, 1,1),
|
||||
video::S3DVertex(+0.5,-0.5,+0.5, 0,0,1, c, 0,1),
|
||||
video::S3DVertex(+0.5,+0.5,+0.5, 0,0,1, c, 0,0),
|
||||
video::S3DVertex(-0.5,+0.5,+0.5, 0,0,1, c, 1,0),
|
||||
// Front
|
||||
video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
|
||||
video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
|
||||
video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
|
||||
video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
|
||||
};
|
||||
|
||||
u16 indices[6] = {0,1,2,2,3,0};
|
||||
|
||||
scene::SMesh *mesh = new scene::SMesh();
|
||||
for (u32 i=0; i<6; ++i)
|
||||
{
|
||||
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
|
||||
buf->append(vertices + 4 * i, 4, indices, 6);
|
||||
mesh->addMeshBuffer(buf);
|
||||
buf->drop();
|
||||
}
|
||||
scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
|
||||
mesh->drop();
|
||||
scaleMesh(anim_mesh, scale); // also recalculates bounding box
|
||||
return anim_mesh;
|
||||
}
|
||||
|
||||
static scene::IAnimatedMesh* extrudeARGB(u32 twidth, u32 theight, u8 *data)
|
||||
{
|
||||
const s32 argb_wstep = 4 * twidth;
|
||||
const s32 alpha_threshold = 1;
|
||||
|
||||
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
|
||||
video::SColor c(255,255,255,255);
|
||||
|
||||
// Front and back
|
||||
{
|
||||
video::S3DVertex vertices[8] =
|
||||
{
|
||||
video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
|
||||
video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
|
||||
video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
|
||||
video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
|
||||
video::S3DVertex(+0.5,-0.5,+0.5, 0,0,+1, c, 1,1),
|
||||
video::S3DVertex(+0.5,+0.5,+0.5, 0,0,+1, c, 1,0),
|
||||
video::S3DVertex(-0.5,+0.5,+0.5, 0,0,+1, c, 0,0),
|
||||
video::S3DVertex(-0.5,-0.5,+0.5, 0,0,+1, c, 0,1),
|
||||
};
|
||||
u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
|
||||
buf->append(vertices, 8, indices, 12);
|
||||
}
|
||||
|
||||
// "Interior"
|
||||
// (add faces where a solid pixel is next to a transparent one)
|
||||
u8 *solidity = new u8[(twidth+2) * (theight+2)];
|
||||
u32 wstep = twidth + 2;
|
||||
for (u32 y = 0; y < theight + 2; ++y)
|
||||
{
|
||||
u8 *scanline = solidity + y * wstep;
|
||||
if (y == 0 || y == theight + 1)
|
||||
{
|
||||
for (u32 x = 0; x < twidth + 2; ++x)
|
||||
scanline[x] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
scanline[0] = 0;
|
||||
u8 *argb_scanline = data + (y - 1) * argb_wstep;
|
||||
for (u32 x = 0; x < twidth; ++x)
|
||||
scanline[x+1] = (argb_scanline[x*4+3] >= alpha_threshold);
|
||||
scanline[twidth + 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// without this, there would be occasional "holes" in the mesh
|
||||
f32 eps = 0.01;
|
||||
|
||||
for (u32 y = 0; y <= theight; ++y)
|
||||
{
|
||||
u8 *scanline = solidity + y * wstep + 1;
|
||||
for (u32 x = 0; x <= twidth; ++x)
|
||||
{
|
||||
if (scanline[x] && !scanline[x + wstep])
|
||||
{
|
||||
u32 xx = x + 1;
|
||||
while (scanline[xx] && !scanline[xx + wstep])
|
||||
++xx;
|
||||
f32 vx1 = (x - eps) / (f32) twidth - 0.5;
|
||||
f32 vx2 = (xx + eps) / (f32) twidth - 0.5;
|
||||
f32 vy = 0.5 - (y - eps) / (f32) theight;
|
||||
f32 tx1 = x / (f32) twidth;
|
||||
f32 tx2 = xx / (f32) twidth;
|
||||
f32 ty = (y - 0.5) / (f32) theight;
|
||||
video::S3DVertex vertices[8] =
|
||||
{
|
||||
video::S3DVertex(vx1,vy,-0.5, 0,-1,0, c, tx1,ty),
|
||||
video::S3DVertex(vx2,vy,-0.5, 0,-1,0, c, tx2,ty),
|
||||
video::S3DVertex(vx2,vy,+0.5, 0,-1,0, c, tx2,ty),
|
||||
video::S3DVertex(vx1,vy,+0.5, 0,-1,0, c, tx1,ty),
|
||||
};
|
||||
u16 indices[6] = {0,1,2,2,3,0};
|
||||
buf->append(vertices, 4, indices, 6);
|
||||
x = xx - 1;
|
||||
}
|
||||
if (!scanline[x] && scanline[x + wstep])
|
||||
{
|
||||
u32 xx = x + 1;
|
||||
while (!scanline[xx] && scanline[xx + wstep])
|
||||
++xx;
|
||||
f32 vx1 = (x - eps) / (f32) twidth - 0.5;
|
||||
f32 vx2 = (xx + eps) / (f32) twidth - 0.5;
|
||||
f32 vy = 0.5 - (y + eps) / (f32) theight;
|
||||
f32 tx1 = x / (f32) twidth;
|
||||
f32 tx2 = xx / (f32) twidth;
|
||||
f32 ty = (y + 0.5) / (f32) theight;
|
||||
video::S3DVertex vertices[8] =
|
||||
{
|
||||
video::S3DVertex(vx1,vy,-0.5, 0,1,0, c, tx1,ty),
|
||||
video::S3DVertex(vx1,vy,+0.5, 0,1,0, c, tx1,ty),
|
||||
video::S3DVertex(vx2,vy,+0.5, 0,1,0, c, tx2,ty),
|
||||
video::S3DVertex(vx2,vy,-0.5, 0,1,0, c, tx2,ty),
|
||||
};
|
||||
u16 indices[6] = {0,1,2,2,3,0};
|
||||
buf->append(vertices, 4, indices, 6);
|
||||
x = xx - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 x = 0; x <= twidth; ++x)
|
||||
{
|
||||
u8 *scancol = solidity + x + wstep;
|
||||
for (u32 y = 0; y <= theight; ++y)
|
||||
{
|
||||
if (scancol[y * wstep] && !scancol[y * wstep + 1])
|
||||
{
|
||||
u32 yy = y + 1;
|
||||
while (scancol[yy * wstep] && !scancol[yy * wstep + 1])
|
||||
++yy;
|
||||
f32 vx = (x - eps) / (f32) twidth - 0.5;
|
||||
f32 vy1 = 0.5 - (y - eps) / (f32) theight;
|
||||
f32 vy2 = 0.5 - (yy + eps) / (f32) theight;
|
||||
f32 tx = (x - 0.5) / (f32) twidth;
|
||||
f32 ty1 = y / (f32) theight;
|
||||
f32 ty2 = yy / (f32) theight;
|
||||
video::S3DVertex vertices[8] =
|
||||
{
|
||||
video::S3DVertex(vx,vy1,-0.5, 1,0,0, c, tx,ty1),
|
||||
video::S3DVertex(vx,vy1,+0.5, 1,0,0, c, tx,ty1),
|
||||
video::S3DVertex(vx,vy2,+0.5, 1,0,0, c, tx,ty2),
|
||||
video::S3DVertex(vx,vy2,-0.5, 1,0,0, c, tx,ty2),
|
||||
};
|
||||
u16 indices[6] = {0,1,2,2,3,0};
|
||||
buf->append(vertices, 4, indices, 6);
|
||||
y = yy - 1;
|
||||
}
|
||||
if (!scancol[y * wstep] && scancol[y * wstep + 1])
|
||||
{
|
||||
u32 yy = y + 1;
|
||||
while (!scancol[yy * wstep] && scancol[yy * wstep + 1])
|
||||
++yy;
|
||||
f32 vx = (x + eps) / (f32) twidth - 0.5;
|
||||
f32 vy1 = 0.5 - (y - eps) / (f32) theight;
|
||||
f32 vy2 = 0.5 - (yy + eps) / (f32) theight;
|
||||
f32 tx = (x + 0.5) / (f32) twidth;
|
||||
f32 ty1 = y / (f32) theight;
|
||||
f32 ty2 = yy / (f32) theight;
|
||||
video::S3DVertex vertices[8] =
|
||||
{
|
||||
video::S3DVertex(vx,vy1,-0.5, -1,0,0, c, tx,ty1),
|
||||
video::S3DVertex(vx,vy2,-0.5, -1,0,0, c, tx,ty2),
|
||||
video::S3DVertex(vx,vy2,+0.5, -1,0,0, c, tx,ty2),
|
||||
video::S3DVertex(vx,vy1,+0.5, -1,0,0, c, tx,ty1),
|
||||
};
|
||||
u16 indices[6] = {0,1,2,2,3,0};
|
||||
buf->append(vertices, 4, indices, 6);
|
||||
y = yy - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add to mesh
|
||||
scene::SMesh *mesh = new scene::SMesh();
|
||||
mesh->addMeshBuffer(buf);
|
||||
buf->drop();
|
||||
scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
|
||||
mesh->drop();
|
||||
return anim_mesh;
|
||||
}
|
||||
|
||||
scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture,
|
||||
video::IVideoDriver *driver, v3f scale)
|
||||
{
|
||||
scene::IAnimatedMesh *mesh = NULL;
|
||||
core::dimension2d<u32> size = texture->getSize();
|
||||
video::ECOLOR_FORMAT format = texture->getColorFormat();
|
||||
if (format == video::ECF_A8R8G8B8)
|
||||
{
|
||||
// Texture is in the correct color format, we can pass it
|
||||
// to extrudeARGB right away.
|
||||
void *data = texture->lock(MY_ETLM_READ_ONLY);
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
mesh = extrudeARGB(size.Width, size.Height, (u8*) data);
|
||||
texture->unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
video::IImage *img1 = driver->createImageFromData(format, size, texture->lock(MY_ETLM_READ_ONLY));
|
||||
if (img1 == NULL)
|
||||
return NULL;
|
||||
|
||||
// img1 is in the texture's color format, convert to 8-bit ARGB
|
||||
video::IImage *img2 = driver->createImage(video::ECF_A8R8G8B8, size);
|
||||
if (img2 != NULL)
|
||||
{
|
||||
img1->copyTo(img2);
|
||||
img1->drop();
|
||||
|
||||
mesh = extrudeARGB(size.Width, size.Height, (u8*) img2->lock());
|
||||
img2->unlock();
|
||||
img2->drop();
|
||||
}
|
||||
img1->drop();
|
||||
}
|
||||
scaleMesh(mesh, scale); // also recalculates bounding box
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void scaleMesh(scene::IMesh *mesh, v3f scale)
|
||||
{
|
||||
if(mesh == NULL)
|
||||
return;
|
||||
|
||||
core::aabbox3d<f32> bbox;
|
||||
bbox.reset(0,0,0);
|
||||
|
||||
u16 mc = mesh->getMeshBufferCount();
|
||||
for(u16 j=0; j<mc; j++)
|
||||
{
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
|
||||
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
|
||||
u16 vc = buf->getVertexCount();
|
||||
for(u16 i=0; i<vc; i++)
|
||||
{
|
||||
vertices[i].Pos *= scale;
|
||||
}
|
||||
buf->recalculateBoundingBox();
|
||||
|
||||
// calculate total bounding box
|
||||
if(j == 0)
|
||||
bbox = buf->getBoundingBox();
|
||||
else
|
||||
bbox.addInternalBox(buf->getBoundingBox());
|
||||
}
|
||||
mesh->setBoundingBox(bbox);
|
||||
}
|
||||
|
||||
void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
|
||||
{
|
||||
if(mesh == NULL)
|
||||
return;
|
||||
|
||||
u16 mc = mesh->getMeshBufferCount();
|
||||
for(u16 j=0; j<mc; j++)
|
||||
{
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
|
||||
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
|
||||
u16 vc = buf->getVertexCount();
|
||||
for(u16 i=0; i<vc; i++)
|
||||
{
|
||||
vertices[i].Color = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setMeshColorByNormalXYZ(scene::IMesh *mesh,
|
||||
const video::SColor &colorX,
|
||||
const video::SColor &colorY,
|
||||
const video::SColor &colorZ)
|
||||
{
|
||||
if(mesh == NULL)
|
||||
return;
|
||||
|
||||
u16 mc = mesh->getMeshBufferCount();
|
||||
for(u16 j=0; j<mc; j++)
|
||||
{
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
|
||||
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
|
||||
u16 vc = buf->getVertexCount();
|
||||
for(u16 i=0; i<vc; i++)
|
||||
{
|
||||
f32 x = fabs(vertices[i].Normal.X);
|
||||
f32 y = fabs(vertices[i].Normal.Y);
|
||||
f32 z = fabs(vertices[i].Normal.Z);
|
||||
if(x >= y && x >= z)
|
||||
vertices[i].Color = colorX;
|
||||
else if(y >= z)
|
||||
vertices[i].Color = colorY;
|
||||
else
|
||||
vertices[i].Color = colorZ;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
66
src/mesh.h
Normal file
66
src/mesh.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MESH_HEADER
|
||||
#define MESH_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
|
||||
/*
|
||||
Create a new cube mesh.
|
||||
Vertices are at (+-scale.X/2, +-scale.Y/2, +-scale.Z/2).
|
||||
|
||||
The resulting mesh has 6 materials (up, down, right, left, back, front)
|
||||
which must be defined by the caller.
|
||||
*/
|
||||
scene::IAnimatedMesh* createCubeMesh(v3f scale);
|
||||
|
||||
/*
|
||||
Create a new extruded mesh from a texture.
|
||||
Maximum bounding box is (+-scale.X/2, +-scale.Y/2, +-scale.Z).
|
||||
Thickness is in Z direction.
|
||||
|
||||
The resulting mesh has 1 material which must be defined by the caller.
|
||||
*/
|
||||
scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture,
|
||||
video::IVideoDriver *driver, v3f scale);
|
||||
|
||||
/*
|
||||
Multiplies each vertex coordinate by the specified scaling factors
|
||||
(componentwise vector multiplication).
|
||||
*/
|
||||
void scaleMesh(scene::IMesh *mesh, v3f scale);
|
||||
|
||||
/*
|
||||
Set a constant color for all vertices in the mesh
|
||||
*/
|
||||
void setMeshColor(scene::IMesh *mesh, const video::SColor &color);
|
||||
|
||||
/*
|
||||
Set the color of all vertices in the mesh.
|
||||
For each vertex, determine the largest absolute entry in
|
||||
the normal vector, and choose one of colorX, colorY or
|
||||
colorZ accordingly.
|
||||
*/
|
||||
void setMeshColorByNormalXYZ(scene::IMesh *mesh,
|
||||
const video::SColor &colorX,
|
||||
const video::SColor &colorY,
|
||||
const video::SColor &colorZ);
|
||||
|
||||
#endif
|
||||
116
src/mods.cpp
Normal file
116
src/mods.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "mods.h"
|
||||
#include <queue>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include "filesys.h"
|
||||
#include "strfnd.h"
|
||||
#include "log.h"
|
||||
|
||||
// Get a dependency-sorted list of ModSpecs
|
||||
core::list<ModSpec> getMods(core::list<std::string> &modspaths)
|
||||
throw(ModError)
|
||||
{
|
||||
std::queue<ModSpec> mods_satisfied;
|
||||
core::list<ModSpec> mods_unsorted;
|
||||
core::list<ModSpec> mods_sorted;
|
||||
// name, path: For detecting name conflicts
|
||||
std::map<std::string, std::string> mod_names;
|
||||
for(core::list<std::string>::Iterator i = modspaths.begin();
|
||||
i != modspaths.end(); i++){
|
||||
std::string modspath = *i;
|
||||
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(modspath);
|
||||
for(u32 j=0; j<dirlist.size(); j++){
|
||||
if(!dirlist[j].dir)
|
||||
continue;
|
||||
std::string modname = dirlist[j].name;
|
||||
std::string modpath = modspath + DIR_DELIM + modname;
|
||||
// Detect mod name conflicts
|
||||
{
|
||||
std::map<std::string, std::string>::const_iterator i;
|
||||
i = mod_names.find(modname);
|
||||
if(i != mod_names.end()){
|
||||
std::string s;
|
||||
infostream<<"WARNING: Mod name conflict detected: "
|
||||
<<std::endl
|
||||
<<"Already loaded: "<<i->second<<std::endl
|
||||
<<"Will not load: "<<modpath<<std::endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
std::set<std::string> depends;
|
||||
std::ifstream is((modpath+DIR_DELIM+"depends.txt").c_str(),
|
||||
std::ios_base::binary);
|
||||
while(is.good()){
|
||||
std::string dep;
|
||||
std::getline(is, dep);
|
||||
dep = trim(dep);
|
||||
if(dep != "")
|
||||
depends.insert(dep);
|
||||
}
|
||||
ModSpec spec(modname, modpath, depends);
|
||||
mods_unsorted.push_back(spec);
|
||||
if(depends.empty())
|
||||
mods_satisfied.push(spec);
|
||||
mod_names[modname] = modpath;
|
||||
}
|
||||
}
|
||||
// Sort by depencencies
|
||||
while(!mods_satisfied.empty()){
|
||||
ModSpec mod = mods_satisfied.front();
|
||||
mods_satisfied.pop();
|
||||
mods_sorted.push_back(mod);
|
||||
for(core::list<ModSpec>::Iterator i = mods_unsorted.begin();
|
||||
i != mods_unsorted.end(); i++){
|
||||
ModSpec &mod2 = *i;
|
||||
if(mod2.unsatisfied_depends.empty())
|
||||
continue;
|
||||
mod2.unsatisfied_depends.erase(mod.name);
|
||||
if(!mod2.unsatisfied_depends.empty())
|
||||
continue;
|
||||
mods_satisfied.push(mod2);
|
||||
}
|
||||
}
|
||||
std::ostringstream errs(std::ios::binary);
|
||||
// Check unsatisfied dependencies
|
||||
for(core::list<ModSpec>::Iterator i = mods_unsorted.begin();
|
||||
i != mods_unsorted.end(); i++){
|
||||
ModSpec &mod = *i;
|
||||
if(mod.unsatisfied_depends.empty())
|
||||
continue;
|
||||
errs<<"mod \""<<mod.name
|
||||
<<"\" has unsatisfied dependencies:";
|
||||
for(std::set<std::string>::iterator
|
||||
i = mod.unsatisfied_depends.begin();
|
||||
i != mod.unsatisfied_depends.end(); i++){
|
||||
errs<<" \""<<(*i)<<"\"";
|
||||
}
|
||||
errs<<"."<<std::endl;
|
||||
mods_sorted.push_back(mod);
|
||||
}
|
||||
if(errs.str().size() != 0){
|
||||
throw ModError(errs.str());
|
||||
}
|
||||
return mods_sorted;
|
||||
}
|
||||
|
||||
|
||||
61
src/mods.h
Normal file
61
src/mods.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "irrlichttypes.h"
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <exception>
|
||||
|
||||
class ModError : public std::exception
|
||||
{
|
||||
public:
|
||||
ModError(const std::string &s)
|
||||
{
|
||||
m_s = "ModError: ";
|
||||
m_s += s;
|
||||
}
|
||||
virtual ~ModError() throw()
|
||||
{}
|
||||
virtual const char * what() const throw()
|
||||
{
|
||||
return m_s.c_str();
|
||||
}
|
||||
std::string m_s;
|
||||
};
|
||||
|
||||
struct ModSpec
|
||||
{
|
||||
std::string name;
|
||||
std::string path;
|
||||
std::set<std::string> depends;
|
||||
std::set<std::string> unsatisfied_depends;
|
||||
|
||||
ModSpec(const std::string &name_="", const std::string path_="",
|
||||
const std::set<std::string> &depends_=std::set<std::string>()):
|
||||
name(name_),
|
||||
path(path_),
|
||||
depends(depends_),
|
||||
unsatisfied_depends(depends_)
|
||||
{}
|
||||
};
|
||||
|
||||
// Get a dependency-sorted list of ModSpecs
|
||||
core::list<ModSpec> getMods(core::list<std::string> &modspaths)
|
||||
throw(ModError);
|
||||
|
||||
@@ -31,20 +31,63 @@ extern "C" {
|
||||
#include <lauxlib.h>
|
||||
}
|
||||
|
||||
LuaError::LuaError(lua_State *L, const std::string &s)
|
||||
{
|
||||
m_s = "LuaError: ";
|
||||
m_s += s + "\n";
|
||||
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
|
||||
if(lua_istable(L, -1)){
|
||||
lua_getfield(L, -1, "traceback");
|
||||
if(lua_isfunction(L, -1)){
|
||||
lua_call(L, 0, 1);
|
||||
if(lua_isstring(L, -1)){
|
||||
m_s += lua_tostring(L, -1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
else{
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
void script_error(lua_State *L, const char *fmt, ...)
|
||||
{
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
vfprintf(stderr, fmt, argp);
|
||||
char buf[10000];
|
||||
vsnprintf(buf, 10000, fmt, argp);
|
||||
va_end(argp);
|
||||
lua_close(L);
|
||||
exit(EXIT_FAILURE);
|
||||
//errorstream<<"SCRIPT ERROR: "<<buf;
|
||||
throw LuaError(L, buf);
|
||||
}
|
||||
|
||||
int luaErrorHandler(lua_State *L) {
|
||||
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
lua_getfield(L, -1, "traceback");
|
||||
if (!lua_isfunction(L, -1)) {
|
||||
lua_pop(L, 2);
|
||||
return 1;
|
||||
}
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushinteger(L, 2);
|
||||
lua_call(L, 2, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool script_load(lua_State *L, const char *path)
|
||||
{
|
||||
infostream<<"Loading and running script from "<<path<<std::endl;
|
||||
int ret = luaL_loadfile(L, path) || lua_pcall(L, 0, 0, 0);
|
||||
|
||||
lua_pushcfunction(L, luaErrorHandler);
|
||||
int errorhandler = lua_gettop(L);
|
||||
|
||||
int ret = luaL_loadfile(L, path) || lua_pcall(L, 0, 0, errorhandler);
|
||||
if(ret){
|
||||
errorstream<<"Failed to load and run script from "<<path<<":"<<std::endl;
|
||||
errorstream<<"[LUA] "<<std::endl;
|
||||
|
||||
18
src/script.h
18
src/script.h
@@ -20,8 +20,24 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#ifndef SCRIPT_HEADER
|
||||
#define SCRIPT_HEADER
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
typedef struct lua_State lua_State;
|
||||
//#include <string>
|
||||
|
||||
class LuaError : public std::exception
|
||||
{
|
||||
public:
|
||||
LuaError(lua_State *L, const std::string &s);
|
||||
|
||||
virtual ~LuaError() throw()
|
||||
{}
|
||||
virtual const char * what() const throw()
|
||||
{
|
||||
return m_s.c_str();
|
||||
}
|
||||
std::string m_s;
|
||||
};
|
||||
|
||||
lua_State* script_init();
|
||||
void script_deinit(lua_State *L);
|
||||
|
||||
@@ -107,6 +107,66 @@ class StackUnroller
|
||||
}
|
||||
};
|
||||
|
||||
class ModNameStorer
|
||||
{
|
||||
private:
|
||||
lua_State *L;
|
||||
public:
|
||||
ModNameStorer(lua_State *L_, const std::string modname):
|
||||
L(L_)
|
||||
{
|
||||
// Store current modname in registry
|
||||
lua_pushstring(L, modname.c_str());
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
|
||||
}
|
||||
~ModNameStorer()
|
||||
{
|
||||
// Clear current modname in registry
|
||||
lua_pushnil(L);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
|
||||
}
|
||||
};
|
||||
|
||||
std::string get_current_modname(lua_State *L)
|
||||
{
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
|
||||
std::string modname = "";
|
||||
if(lua_type(L, -1) == LUA_TSTRING)
|
||||
modname = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return modname;
|
||||
}
|
||||
|
||||
void check_modname_prefix(lua_State *L, std::string &name)
|
||||
{
|
||||
if(name.size() == 0)
|
||||
throw LuaError(L, std::string("Name is empty"));
|
||||
|
||||
if(name[0] == ':'){
|
||||
name = name.substr(1);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string modname = get_current_modname(L);
|
||||
assert(modname != "");
|
||||
|
||||
// For __builtin, anything goes
|
||||
if(modname == "__builtin")
|
||||
return;
|
||||
|
||||
if(name.substr(0, modname.size()+1) != modname + ":")
|
||||
throw LuaError(L, std::string("Name \"")+name
|
||||
+"\" does not follow naming conventions: "
|
||||
+"\"modname:\" or \":\" prefix required)");
|
||||
|
||||
std::string subname = name.substr(modname.size()+1);
|
||||
if(!string_allowed(subname, "abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
|
||||
throw LuaError(L, std::string("Name \"")+name
|
||||
+"\" does not follow naming conventions: "
|
||||
+"\"contains unallowed characters)");
|
||||
}
|
||||
|
||||
static v3f readFloatPos(lua_State *L, int index)
|
||||
{
|
||||
v3f pos;
|
||||
@@ -470,7 +530,7 @@ static void inventory_get_list_to_lua(Inventory *inv, const char *name,
|
||||
lua_pushstring(L, item->getItemString().c_str());
|
||||
}
|
||||
if(lua_pcall(L, 2, 0, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,8 +671,9 @@ static int l_register_nodedef_defaults(lua_State *L)
|
||||
// register_entity(name, prototype)
|
||||
static int l_register_entity(lua_State *L)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
infostream<<"register_entity: "<<name<<std::endl;
|
||||
std::string name = luaL_checkstring(L, 1);
|
||||
check_modname_prefix(L, name);
|
||||
//infostream<<"register_entity: "<<name<<std::endl;
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
|
||||
// Get minetest.registered_entities
|
||||
@@ -622,7 +683,7 @@ static int l_register_entity(lua_State *L)
|
||||
int registered_entities = lua_gettop(L);
|
||||
lua_pushvalue(L, 2); // Object = param 2 -> stack top
|
||||
// registered_entities[name] = object
|
||||
lua_setfield(L, registered_entities, name);
|
||||
lua_setfield(L, registered_entities, name.c_str());
|
||||
|
||||
// Get registered object to top of stack
|
||||
lua_pushvalue(L, 2);
|
||||
@@ -703,14 +764,14 @@ class LuaABM : public ActiveBlockModifier
|
||||
lua_pushnumber(L, active_object_count);
|
||||
lua_pushnumber(L, active_object_count_wider);
|
||||
if(lua_pcall(L, 4, 0, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
};
|
||||
|
||||
// register_abm({...})
|
||||
static int l_register_abm(lua_State *L)
|
||||
{
|
||||
infostream<<"register_abm"<<std::endl;
|
||||
//infostream<<"register_abm"<<std::endl;
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
|
||||
// Get minetest.registered_abms
|
||||
@@ -744,8 +805,9 @@ static int l_register_abm(lua_State *L)
|
||||
// register_tool(name, {lots of stuff})
|
||||
static int l_register_tool(lua_State *L)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
infostream<<"register_tool: "<<name<<std::endl;
|
||||
std::string name = luaL_checkstring(L, 1);
|
||||
check_modname_prefix(L, name);
|
||||
//infostream<<"register_tool: "<<name<<std::endl;
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
int table = 2;
|
||||
|
||||
@@ -765,8 +827,9 @@ static int l_register_tool(lua_State *L)
|
||||
// register_craftitem(name, {lots of stuff})
|
||||
static int l_register_craftitem(lua_State *L)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
infostream<<"register_craftitem: "<<name<<std::endl;
|
||||
std::string name = luaL_checkstring(L, 1);
|
||||
check_modname_prefix(L, name);
|
||||
//infostream<<"register_craftitem: "<<name<<std::endl;
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
int table = 2;
|
||||
|
||||
@@ -806,7 +869,7 @@ static int l_register_craftitem(lua_State *L)
|
||||
craftitemdef->registerCraftItem(name, def);
|
||||
|
||||
lua_pushvalue(L, table);
|
||||
scriptapi_add_craftitem(L, name);
|
||||
scriptapi_add_craftitem(L, name.c_str());
|
||||
|
||||
return 0; /* number of results */
|
||||
}
|
||||
@@ -814,8 +877,9 @@ static int l_register_craftitem(lua_State *L)
|
||||
// register_node(name, {lots of stuff})
|
||||
static int l_register_node(lua_State *L)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
infostream<<"register_node: "<<name<<std::endl;
|
||||
std::string name = luaL_checkstring(L, 1);
|
||||
check_modname_prefix(L, name);
|
||||
//infostream<<"register_node: "<<name<<std::endl;
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
int nodedef_table = 2;
|
||||
|
||||
@@ -849,7 +913,7 @@ static int l_register_node(lua_State *L)
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "registered_nodes");
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
lua_pushstring(L, name);
|
||||
lua_pushstring(L, name.c_str());
|
||||
lua_pushvalue(L, nodedef_table);
|
||||
lua_settable(L, -3);
|
||||
|
||||
@@ -1054,7 +1118,7 @@ static int l_register_node(lua_State *L)
|
||||
// register_craft({output=item, recipe={{item00,item10},{item01,item11}})
|
||||
static int l_register_craft(lua_State *L)
|
||||
{
|
||||
infostream<<"register_craft"<<std::endl;
|
||||
//infostream<<"register_craft"<<std::endl;
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
int table0 = 1;
|
||||
|
||||
@@ -1101,7 +1165,10 @@ static int l_register_craft(lua_State *L)
|
||||
width = colcount;
|
||||
} else {
|
||||
if(colcount != width){
|
||||
script_error(L, "error: %s\n", "Invalid crafting recipe");
|
||||
std::string error;
|
||||
error += "Invalid crafting recipe (output=\""
|
||||
+ output + "\")";
|
||||
throw LuaError(L, error);
|
||||
}
|
||||
}
|
||||
// removes value, keeps key for next iteration
|
||||
@@ -2469,6 +2536,24 @@ void scriptapi_export(lua_State *L, Server *server)
|
||||
ObjectRef::Register(L);
|
||||
}
|
||||
|
||||
bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
|
||||
const std::string &modname)
|
||||
{
|
||||
ModNameStorer modnamestorer(L, modname);
|
||||
|
||||
bool success = false;
|
||||
|
||||
try{
|
||||
success = script_load(L, scriptpath.c_str());
|
||||
}
|
||||
catch(LuaError &e){
|
||||
errorstream<<"Error loading mod \""<<modname
|
||||
<<"\": "<<e.what()<<std::endl;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
|
||||
{
|
||||
realitycheck(L);
|
||||
@@ -2549,7 +2634,7 @@ static void dump2(lua_State *L, const char *name)
|
||||
lua_pushvalue(L, -2); // Get previous stack top as first parameter
|
||||
lua_pushstring(L, name);
|
||||
if(lua_pcall(L, 2, 0, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2627,7 +2712,7 @@ bool scriptapi_on_chat_message(lua_State *L, const std::string &name,
|
||||
lua_pushstring(L, name.c_str());
|
||||
lua_pushstring(L, message.c_str());
|
||||
if(lua_pcall(L, 2, 1, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
bool ate = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if(ate)
|
||||
@@ -2660,7 +2745,7 @@ void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player)
|
||||
// Call function
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 1, 0, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
}
|
||||
@@ -2685,7 +2770,7 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
|
||||
// Call function
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 1, 1, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
bool positioning_handled = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if(positioning_handled)
|
||||
@@ -2807,7 +2892,7 @@ bool scriptapi_craftitem_on_drop(lua_State *L, const char *name,
|
||||
objectref_get_or_create(L, dropper);
|
||||
pushFloatPos(L, pos);
|
||||
if(lua_pcall(L, 3, 1, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
result = lua_toboolean(L, -1);
|
||||
}
|
||||
return result;
|
||||
@@ -2831,7 +2916,7 @@ bool scriptapi_craftitem_on_place_on_ground(lua_State *L, const char *name,
|
||||
objectref_get_or_create(L, placer);
|
||||
pushFloatPos(L, pos);
|
||||
if(lua_pcall(L, 3, 1, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
result = lua_toboolean(L, -1);
|
||||
}
|
||||
return result;
|
||||
@@ -2855,7 +2940,7 @@ bool scriptapi_craftitem_on_use(lua_State *L, const char *name,
|
||||
objectref_get_or_create(L, user);
|
||||
pushPointedThing(L, pointed);
|
||||
if(lua_pcall(L, 3, 1, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
result = lua_toboolean(L, -1);
|
||||
}
|
||||
return result;
|
||||
@@ -2885,7 +2970,7 @@ void scriptapi_environment_step(lua_State *L, float dtime)
|
||||
// Call function
|
||||
lua_pushnumber(L, dtime);
|
||||
if(lua_pcall(L, 1, 0, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
}
|
||||
@@ -2920,7 +3005,7 @@ void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode,
|
||||
pushnode(L, newnode, ndef);
|
||||
objectref_get_or_create(L, placer);
|
||||
if(lua_pcall(L, 3, 0, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
}
|
||||
@@ -2955,7 +3040,7 @@ void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode,
|
||||
pushnode(L, oldnode, ndef);
|
||||
objectref_get_or_create(L, digger);
|
||||
if(lua_pcall(L, 3, 0, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
}
|
||||
@@ -2990,7 +3075,7 @@ void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node,
|
||||
pushnode(L, node, ndef);
|
||||
objectref_get_or_create(L, puncher);
|
||||
if(lua_pcall(L, 3, 0, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
}
|
||||
@@ -3016,7 +3101,7 @@ void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp)
|
||||
pushpos(L, minp);
|
||||
pushpos(L, maxp);
|
||||
if(lua_pcall(L, 2, 0, 0))
|
||||
script_error(L, "error: %s\n", lua_tostring(L, -1));
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
// value removed, keep key for next iteration
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ struct PointedThing;
|
||||
class ServerRemotePlayer;
|
||||
|
||||
void scriptapi_export(lua_State *L, Server *server);
|
||||
bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
|
||||
const std::string &modname);
|
||||
void scriptapi_add_environment(lua_State *L, ServerEnvironment *env);
|
||||
|
||||
void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj);
|
||||
|
||||
200
src/server.cpp
200
src/server.cpp
@@ -47,7 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "craftitemdef.h"
|
||||
#include "mapgen.h"
|
||||
#include "content_abm.h"
|
||||
#include "content_sao.h" // For PlayerSAO
|
||||
#include "mods.h"
|
||||
|
||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||
|
||||
@@ -833,92 +833,6 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
|
||||
return checksum;
|
||||
}
|
||||
|
||||
/*
|
||||
Mods
|
||||
*/
|
||||
|
||||
struct ModSpec
|
||||
{
|
||||
std::string name;
|
||||
std::string path;
|
||||
std::set<std::string> depends;
|
||||
std::set<std::string> unsatisfied_depends;
|
||||
|
||||
ModSpec(const std::string &name_="", const std::string path_="",
|
||||
const std::set<std::string> &depends_=std::set<std::string>()):
|
||||
name(name_),
|
||||
path(path_),
|
||||
depends(depends_),
|
||||
unsatisfied_depends(depends_)
|
||||
{}
|
||||
};
|
||||
|
||||
// Get a dependency-sorted list of ModSpecs
|
||||
static core::list<ModSpec> getMods(core::list<std::string> &modspaths)
|
||||
{
|
||||
std::queue<ModSpec> mods_satisfied;
|
||||
core::list<ModSpec> mods_unsorted;
|
||||
core::list<ModSpec> mods_sorted;
|
||||
for(core::list<std::string>::Iterator i = modspaths.begin();
|
||||
i != modspaths.end(); i++){
|
||||
std::string modspath = *i;
|
||||
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(modspath);
|
||||
for(u32 j=0; j<dirlist.size(); j++){
|
||||
if(!dirlist[j].dir)
|
||||
continue;
|
||||
std::string modname = dirlist[j].name;
|
||||
std::string modpath = modspath + DIR_DELIM + modname;
|
||||
std::set<std::string> depends;
|
||||
std::ifstream is((modpath+DIR_DELIM+"depends.txt").c_str(),
|
||||
std::ios_base::binary);
|
||||
while(is.good()){
|
||||
std::string dep;
|
||||
std::getline(is, dep);
|
||||
dep = trim(dep);
|
||||
if(dep != "")
|
||||
depends.insert(dep);
|
||||
}
|
||||
ModSpec spec(modname, modpath, depends);
|
||||
mods_unsorted.push_back(spec);
|
||||
if(depends.empty())
|
||||
mods_satisfied.push(spec);
|
||||
}
|
||||
}
|
||||
// Sort by depencencies
|
||||
while(!mods_satisfied.empty()){
|
||||
ModSpec mod = mods_satisfied.front();
|
||||
mods_satisfied.pop();
|
||||
mods_sorted.push_back(mod);
|
||||
for(core::list<ModSpec>::Iterator i = mods_unsorted.begin();
|
||||
i != mods_unsorted.end(); i++){
|
||||
ModSpec &mod2 = *i;
|
||||
if(mod2.unsatisfied_depends.empty())
|
||||
continue;
|
||||
mod2.unsatisfied_depends.erase(mod.name);
|
||||
if(!mod2.unsatisfied_depends.empty())
|
||||
continue;
|
||||
mods_satisfied.push(mod2);
|
||||
}
|
||||
}
|
||||
// Check unsatisfied dependencies
|
||||
for(core::list<ModSpec>::Iterator i = mods_unsorted.begin();
|
||||
i != mods_unsorted.end(); i++){
|
||||
ModSpec &mod = *i;
|
||||
if(mod.unsatisfied_depends.empty())
|
||||
continue;
|
||||
errorstream<<"mod \""<<mod.name
|
||||
<<"\" has unsatisfied dependencies:";
|
||||
for(std::set<std::string>::iterator
|
||||
i = mod.unsatisfied_depends.begin();
|
||||
i != mod.unsatisfied_depends.end(); i++){
|
||||
errorstream<<" \""<<(*i)<<"\"";
|
||||
}
|
||||
errorstream<<". Loading nevertheless."<<std::endl;
|
||||
mods_sorted.push_back(mod);
|
||||
}
|
||||
return mods_sorted;
|
||||
}
|
||||
|
||||
/*
|
||||
Server
|
||||
*/
|
||||
@@ -961,13 +875,24 @@ Server::Server(
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
JMutexAutoLock conlock(m_con_mutex);
|
||||
|
||||
infostream<<"m_nodedef="<<m_nodedef<<std::endl;
|
||||
|
||||
// Path to builtin.lua
|
||||
std::string builtinpath = porting::path_data + DIR_DELIM + "builtin.lua";
|
||||
// Add default global mod path
|
||||
m_modspaths.push_back(porting::path_data + DIR_DELIM + "mods");
|
||||
|
||||
// Add default global mod search path
|
||||
m_modspaths.push_front(porting::path_data + DIR_DELIM + "mods");
|
||||
// Add world mod search path
|
||||
m_modspaths.push_front(mapsavedir + DIR_DELIM + "worldmods");
|
||||
// Add user mod search path
|
||||
m_modspaths.push_front(porting::path_userdata + DIR_DELIM + "usermods");
|
||||
|
||||
// Print out mod search paths
|
||||
infostream<<"Mod search paths:"<<std::endl;
|
||||
for(core::list<std::string>::Iterator i = m_modspaths.begin();
|
||||
i != m_modspaths.end(); i++){
|
||||
std::string modspath = *i;
|
||||
infostream<<" "<<modspath<<std::endl;
|
||||
}
|
||||
|
||||
// Initialize scripting
|
||||
|
||||
infostream<<"Server: Initializing scripting"<<std::endl;
|
||||
@@ -978,11 +903,11 @@ Server::Server(
|
||||
// Load and run builtin.lua
|
||||
infostream<<"Server: Loading builtin Lua stuff from \""<<builtinpath
|
||||
<<"\""<<std::endl;
|
||||
bool success = script_load(m_lua, builtinpath.c_str());
|
||||
bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
|
||||
if(!success){
|
||||
errorstream<<"Server: Failed to load and run "
|
||||
<<builtinpath<<std::endl;
|
||||
assert(0);
|
||||
throw ModError("Failed to load and run "+builtinpath);
|
||||
}
|
||||
// Load and run "mod" scripts
|
||||
core::list<ModSpec> mods = getMods(m_modspaths);
|
||||
@@ -991,11 +916,11 @@ Server::Server(
|
||||
ModSpec mod = *i;
|
||||
infostream<<"Server: Loading mod \""<<mod.name<<"\""<<std::endl;
|
||||
std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
|
||||
bool success = script_load(m_lua, scriptpath.c_str());
|
||||
bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
|
||||
if(!success){
|
||||
errorstream<<"Server: Failed to load and run "
|
||||
<<scriptpath<<std::endl;
|
||||
assert(0);
|
||||
throw ModError("Failed to load and run "+scriptpath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1283,6 +1208,8 @@ void Server::AsyncRunStep()
|
||||
JMutexAutoLock lock(m_env_mutex);
|
||||
JMutexAutoLock lock2(m_con_mutex);
|
||||
|
||||
ScopeProfiler sp(g_profiler, "Server: handle players");
|
||||
|
||||
//float player_max_speed = BS * 4.0; // Normal speed
|
||||
float player_max_speed = BS * 20; // Fast speed
|
||||
float player_max_speed_up = BS * 20;
|
||||
@@ -1332,7 +1259,7 @@ void Server::AsyncRunStep()
|
||||
}
|
||||
|
||||
/*
|
||||
Handle player HPs
|
||||
Handle player HPs (die if hp=0)
|
||||
*/
|
||||
HandlePlayerHP(player, 0);
|
||||
|
||||
@@ -1346,6 +1273,15 @@ void Server::AsyncRunStep()
|
||||
if(player->m_hp_not_sent){
|
||||
SendPlayerHP(player);
|
||||
}
|
||||
|
||||
/*
|
||||
Add to environment if is not in respawn screen
|
||||
*/
|
||||
if(!player->m_is_in_environment && !player->m_respawn_active){
|
||||
player->m_removed = false;
|
||||
player->setId(0);
|
||||
m_env->addActiveObject(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1591,7 +1527,7 @@ void Server::AsyncRunStep()
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
JMutexAutoLock conlock(m_con_mutex);
|
||||
|
||||
//ScopeProfiler sp(g_profiler, "Server: sending object messages");
|
||||
ScopeProfiler sp(g_profiler, "Server: sending object messages");
|
||||
|
||||
// Key = object id
|
||||
// Value = data sent by object
|
||||
@@ -2125,11 +2061,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
return;
|
||||
}
|
||||
|
||||
// Add PlayerSAO
|
||||
player->m_removed = false;
|
||||
player->setId(0);
|
||||
m_env->addActiveObject(player);
|
||||
|
||||
/*
|
||||
Answer with a TOCLIENT_INIT
|
||||
*/
|
||||
@@ -2885,10 +2816,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
|
||||
actionstream<<player->getName()<<" respawns at "
|
||||
<<PP(player->getPosition()/BS)<<std::endl;
|
||||
|
||||
srp->m_removed = false;
|
||||
srp->setId(0);
|
||||
m_env->addActiveObject(srp);
|
||||
|
||||
// ActiveObject is added to environment in AsyncRunStep after
|
||||
// the previous addition has been succesfully removed
|
||||
}
|
||||
else if(command == TOSERVER_INTERACT)
|
||||
{
|
||||
@@ -3983,6 +3913,7 @@ void Server::BroadcastChatMessage(const std::wstring &message)
|
||||
void Server::SendPlayerHP(Player *player)
|
||||
{
|
||||
SendHP(m_con, player->peer_id, player->hp);
|
||||
static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
|
||||
}
|
||||
|
||||
void Server::SendMovePlayer(Player *player)
|
||||
@@ -4381,39 +4312,41 @@ void Server::HandlePlayerHP(Player *player, s16 damage)
|
||||
if(srp->m_respawn_active)
|
||||
return;
|
||||
|
||||
if(damage == 0)
|
||||
return;
|
||||
|
||||
if(player->hp > damage)
|
||||
{
|
||||
player->hp -= damage;
|
||||
SendPlayerHP(player);
|
||||
return;
|
||||
}
|
||||
|
||||
infostream<<"Server::HandlePlayerHP(): Player "
|
||||
<<player->getName()<<" dies"<<std::endl;
|
||||
|
||||
player->hp = 0;
|
||||
|
||||
//TODO: Throw items around
|
||||
|
||||
// Handle players that are not connected
|
||||
if(player->peer_id == PEER_ID_INEXISTENT){
|
||||
RespawnPlayer(player);
|
||||
return;
|
||||
}
|
||||
|
||||
SendPlayerHP(player);
|
||||
|
||||
RemoteClient *client = getClient(player->peer_id);
|
||||
if(client->net_proto_version >= 3)
|
||||
{
|
||||
SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
|
||||
srp->m_removed = true;
|
||||
srp->m_respawn_active = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
infostream<<"Server::HandlePlayerHP(): Player "
|
||||
<<player->getName()<<" dies"<<std::endl;
|
||||
|
||||
player->hp = 0;
|
||||
|
||||
//TODO: Throw items around
|
||||
|
||||
// Handle players that are not connected
|
||||
if(player->peer_id == PEER_ID_INEXISTENT){
|
||||
RespawnPlayer(player);
|
||||
return;
|
||||
}
|
||||
|
||||
SendPlayerHP(player);
|
||||
|
||||
RemoteClient *client = getClient(player->peer_id);
|
||||
if(client->net_proto_version >= 3)
|
||||
{
|
||||
SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
|
||||
srp->m_removed = true;
|
||||
srp->m_respawn_active = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
RespawnPlayer(player);
|
||||
}
|
||||
RespawnPlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4891,7 +4824,8 @@ void Server::handlePeerChange(PeerChange &c)
|
||||
//SendPlayerInfos();
|
||||
|
||||
// Send leave chat message to all remaining clients
|
||||
BroadcastChatMessage(message);
|
||||
if(message.length() != 0)
|
||||
BroadcastChatMessage(message);
|
||||
|
||||
} // PEER_REMOVED
|
||||
else
|
||||
|
||||
@@ -326,6 +326,10 @@ void cmd_setclearpassword(std::wostringstream &os,
|
||||
|
||||
ctx->server->setPlayerPassword(playername, password);
|
||||
|
||||
std::wostringstream msg;
|
||||
msg<<ctx->player->getName()<<L" changed your password";
|
||||
ctx->server->notifyPlayer(playername.c_str(), msg.str());
|
||||
|
||||
os<<L"-!- Password change for "<<narrow_to_wide(playername)<<" successful";
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "log.h"
|
||||
#include "nodedef.h" // For init_contentfeatures
|
||||
#include "content_mapnode.h" // For content_mapnode_init
|
||||
#include "mods.h"
|
||||
|
||||
/*
|
||||
Settings.
|
||||
@@ -365,6 +366,10 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
errorstream<<"Connection timed out."<<std::endl;
|
||||
}
|
||||
catch(ModError &e)
|
||||
{
|
||||
errorstream<<e.what()<<std::endl;
|
||||
}
|
||||
|
||||
END_DEBUG_EXCEPTION_HANDLER(errorstream)
|
||||
|
||||
|
||||
@@ -92,9 +92,9 @@ class ServerRemotePlayer : public Player, public ServerActiveObject
|
||||
bool m_inventory_not_sent;
|
||||
bool m_hp_not_sent;
|
||||
bool m_respawn_active;
|
||||
bool m_is_in_environment;
|
||||
|
||||
private:
|
||||
bool m_is_in_environment;
|
||||
bool m_position_not_sent;
|
||||
};
|
||||
|
||||
|
||||
38
src/tile.cpp
38
src/tile.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "filesys.h"
|
||||
#include "utility.h"
|
||||
#include "settings.h"
|
||||
#include "mesh.h"
|
||||
#include <ICameraSceneNode.h>
|
||||
#include "log.h"
|
||||
#include "mapnode.h" // For texture atlas making
|
||||
@@ -1468,11 +1469,14 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||
assert(img_top && img_left && img_right);
|
||||
|
||||
// Create textures from images
|
||||
// TODO: Use them all
|
||||
video::ITexture *texture_top = driver->addTexture(
|
||||
(imagename_top + "__temp__").c_str(), img_top);
|
||||
assert(texture_top);
|
||||
|
||||
video::ITexture *texture_left = driver->addTexture(
|
||||
(imagename_left + "__temp__").c_str(), img_left);
|
||||
video::ITexture *texture_right = driver->addTexture(
|
||||
(imagename_right + "__temp__").c_str(), img_right);
|
||||
assert(texture_top && texture_left && texture_right);
|
||||
|
||||
// Drop images
|
||||
img_top->drop();
|
||||
img_left->drop();
|
||||
@@ -1499,17 +1503,24 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||
Create scene:
|
||||
- An unit cube is centered at 0,0,0
|
||||
- Camera looks at cube from Y+, Z- towards Y-, Z+
|
||||
NOTE: Cube has to be changed to something else because
|
||||
the textures cannot be set individually (or can they?)
|
||||
*/
|
||||
|
||||
scene::ISceneNode* cube = smgr->addCubeSceneNode(1.0, NULL, -1,
|
||||
v3f(0,0,0), v3f(0, 45, 0));
|
||||
scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1));
|
||||
setMeshColor(cube, video::SColor(255, 255, 255, 255));
|
||||
|
||||
scene::IMeshSceneNode* cubenode = smgr->addMeshSceneNode(cube, NULL, -1, v3f(0,0,0), v3f(0,45,0), v3f(1,1,1), true);
|
||||
cube->drop();
|
||||
|
||||
// Set texture of cube
|
||||
cube->setMaterialTexture(0, texture_top);
|
||||
//cube->setMaterialFlag(video::EMF_LIGHTING, false);
|
||||
cube->setMaterialFlag(video::EMF_ANTI_ALIASING, false);
|
||||
cube->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
cubenode->getMaterial(0).setTexture(0, texture_top);
|
||||
cubenode->getMaterial(1).setTexture(0, texture_top);
|
||||
cubenode->getMaterial(2).setTexture(0, texture_right);
|
||||
cubenode->getMaterial(3).setTexture(0, texture_right);
|
||||
cubenode->getMaterial(4).setTexture(0, texture_left);
|
||||
cubenode->getMaterial(5).setTexture(0, texture_left);
|
||||
cubenode->setMaterialFlag(video::EMF_LIGHTING, true);
|
||||
cubenode->setMaterialFlag(video::EMF_ANTI_ALIASING, true);
|
||||
cubenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, true);
|
||||
|
||||
scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
|
||||
v3f(0, 1.0, -1.5), v3f(0, 0, 0));
|
||||
@@ -1519,7 +1530,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||
camera->setProjectionMatrix(pm, true);
|
||||
|
||||
/*scene::ILightSceneNode *light =*/ smgr->addLightSceneNode(0,
|
||||
v3f(-50, 100, 0), video::SColorf(0.5,0.5,0.5), 1000);
|
||||
v3f(-50, 100, -75), video::SColorf(0.5,0.5,0.5), 1000);
|
||||
|
||||
smgr->setAmbientLight(video::SColorf(0.2,0.2,0.2));
|
||||
|
||||
@@ -1540,8 +1551,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||
driver->setRenderTarget(0, true, true, 0);
|
||||
|
||||
// Free textures of images
|
||||
// TODO: When all are used, free them all
|
||||
driver->removeTexture(texture_top);
|
||||
driver->removeTexture(texture_left);
|
||||
driver->removeTexture(texture_right);
|
||||
|
||||
// Create image of render target
|
||||
video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
|
||||
|
||||
@@ -172,27 +172,6 @@ int myrand_range(int min, int max)
|
||||
return (myrand()%(max-min+1))+min;
|
||||
}
|
||||
|
||||
#ifndef SERVER
|
||||
// Sets the color of all vertices in the mesh
|
||||
void setMeshVerticesColor(scene::IMesh* mesh, video::SColor& color)
|
||||
{
|
||||
if(mesh == NULL)
|
||||
return;
|
||||
|
||||
u16 mc = mesh->getMeshBufferCount();
|
||||
for(u16 j=0; j<mc; j++)
|
||||
{
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
|
||||
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
|
||||
u16 vc = buf->getVertexCount();
|
||||
for(u16 i=0; i<vc; i++)
|
||||
{
|
||||
vertices[i].Color = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
blockpos: position of block in block coordinates
|
||||
camera_pos: position of camera in nodes
|
||||
|
||||
@@ -694,11 +694,6 @@ class TimeTaker
|
||||
u32 *m_result;
|
||||
};
|
||||
|
||||
#ifndef SERVER
|
||||
// Sets the color of all vertices in the mesh
|
||||
void setMeshVerticesColor(scene::IMesh* mesh, video::SColor& color);
|
||||
#endif
|
||||
|
||||
// Calculates the borders of a "d-radius" cube
|
||||
inline void getFacePositions(core::list<v3s16> &list, u16 d)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user