Compare commits

...

21 Commits

Author SHA1 Message Date
Perttu Ahola
fdf7b3bcdf Call this 0.4.dev-20111203-3 2011-12-03 12:02:45 +02:00
Perttu Ahola
871e6c0c73 On SIGINT in main menu, don't connect before shutting down 2011-12-03 12:02:27 +02:00
Kahrl
392485aa45 inventorycube: use all three specified textures; also moved mesh creation / modification functions to mesh.cpp; in lua, inventorycube is now called minetest.inventorycube 2011-12-03 11:47:37 +02:00
Kahrl
275a348b75 Do not broadcast an empty chat message when someone tries to log in with the wrong password 2011-12-03 11:47:19 +02:00
Kahrl
189689716c Notify player whose password is being changed 2011-12-03 11:47:19 +02:00
Perttu Ahola
3965d432ca Call this 0.4.dev-20111203-2 2011-12-03 11:45:26 +02:00
Perttu Ahola
746b960c0d Note about debug.txt in error message dialog when mod fails to load 2011-12-03 11:44:47 +02:00
Perttu Ahola
760416b81f Change naming convention to be modname:* instead of modname_* (sorry modders!) 2011-12-03 11:41:52 +02:00
Perttu Ahola
1c785c32ef Fix note about run-in-place mod search path in mods/default/init.lua 2011-12-03 04:00:42 +02:00
Perttu Ahola
cd608b1877 Set version 0.4.dev-20111203-1 2011-12-03 03:46:19 +02:00
Perttu Ahola
c6dd75ccfb Add usermods/ to mod search paths and print out the paths at server startup 2011-12-03 03:43:20 +02:00
Perttu Ahola
6b2023dc3e Properly handle mod name conflicts 2011-12-03 03:32:30 +02:00
Perttu Ahola
2f4a92d701 Better mod loading error handling 2011-12-03 03:23:14 +02:00
Perttu Ahola
324c544922 Add world/mods to mod search path 2011-12-03 02:55:54 +02:00
Perttu Ahola
fbbbcf97d8 Remove accidental stupid naming in craftitem example 2011-12-03 02:48:06 +02:00
Perttu Ahola
d96cd236f3 Enforced mod global naming convention and better error reporting 2011-12-03 02:45:55 +02:00
Perttu Ahola
581f950e10 Fix script error reporting a bit 2011-12-02 22:49:54 +02:00
Perttu Ahola
9344816bd6 Fix ActiveObject creation for fast player respawns 2011-12-02 17:30:22 +02:00
Perttu Ahola
67c21fc42f Fix sending of player hp (was sent all the time) 2011-12-02 17:19:42 +02:00
Perttu Ahola
c2d266efc6 Remove unnecessary debug output from mods/default/init.lua 2011-12-02 16:24:56 +02:00
Perttu Ahola
ec1859b095 Show bare hand when no item is selected 2011-12-02 15:20:42 +02:00
26 changed files with 1110 additions and 655 deletions

View File

@@ -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} ***")

View File

@@ -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
--

View File

@@ -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

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

View File

@@ -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,

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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
View 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
View 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
View 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
View 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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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
}
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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";
}

View File

@@ -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)

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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

View File

@@ -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)
{