Compare commits

...

68 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
Perttu Ahola
bc00cdeb2c Set version to 0.4.dev-20111202-1 2011-12-02 13:00:42 +02:00
Perttu Ahola
3e6e35f383 Fix mod licensing and add a mention about sound licensing in README.txt 2011-12-02 12:58:46 +02:00
Perttu Ahola
b9e8e20c9c Script-defined creative inventory 2011-12-02 12:43:57 +02:00
Perttu Ahola
932988af46 Rename "build" privilege to "interact" (backwards-compatibly, of course) 2011-12-02 12:18:19 +02:00
Perttu Ahola
69bc9224db Rename "NodeItem"/"ToolItem"/"CraftItem" to "node"/"tool"/"craft" 2011-12-02 12:12:07 +02:00
Perttu Ahola
a17efe6e8f Remove obsolete createPickedUpItem() 2011-12-02 11:54:23 +02:00
Perttu Ahola
e8b0722137 Add time_from_last_punch to Lua API 2011-12-02 11:51:41 +02:00
Perttu Ahola
ed128fff26 Add a note about mods being under CC BY-SA 3.0 like textures 2011-12-02 11:40:04 +02:00
Mark Holmquist
a465fd5b99 + middle-click now empties the inventory slot properly 2011-12-02 11:31:10 +02:00
Perttu Ahola
9af0142a36 Add enable_pvp setting 2011-12-02 11:25:47 +02:00
Perttu Ahola
34fd47887e Make unlimited player transfer distance configurable 2011-12-02 11:22:09 +02:00
Perttu Ahola
2dc9a0c724 Fix player double damage 2011-12-02 11:16:51 +02:00
Perttu Ahola
c357985135 Make hitting players make a visual damage flash to the player texture and the screen of the local player 2011-12-02 10:57:40 +02:00
Perttu Ahola
ae2b7f9523 Don't hide players in pitch black (like oerkkis) 2011-12-02 10:45:43 +02:00
Perttu Ahola
5344dec760 Move ServerRemotePlayer to a separate file 2011-12-02 10:44:20 +02:00
Perttu Ahola
89bc306632 Fix /give(me) commands a bit in default mod 2011-12-02 02:17:01 +02:00
Perttu Ahola
dc05b106f2 Fix the previous commit 2011-12-02 02:04:25 +02:00
Perttu Ahola
a416cf7c45 Enforce PLAYER_INVENTORY_SIZE in ObjectRef::l_inventory_set_list 2011-12-02 02:01:46 +02:00
Perttu Ahola
09010410cf Print out PROTOCOL_VERSIONs if server is incompatible with client 2011-12-02 01:24:54 +02:00
Perttu Ahola
f8bbecebf5 Higher default map save and unload interval 2011-12-02 01:20:54 +02:00
Perttu Ahola
9d67037570 Don't send objects or map data before definitions have been sent 2011-12-02 01:18:25 +02:00
Perttu Ahola
e4daa4c065 Make players be again visible from a long distance 2011-12-02 01:08:14 +02:00
Perttu Ahola
08a10b8a6a Remove stuff made obsolete by making players more ActiveObject-like and raise protocol version number by one (because it is not compatible at all anymore) 2011-12-01 23:55:57 +02:00
Perttu Ahola
af32240545 Players are more like objects + related stuff 2011-12-01 23:33:48 +02:00
Perttu Ahola
ee0d3bacbc Player-is-SAO WIP 2011-12-01 18:23:58 +02:00
Perttu Ahola
9dcfa882b1 Fix non-fancy leaves not making faces with water 2011-12-01 14:48:52 +02:00
Perttu Ahola
cb589b1f99 Make non-fancy leaf texture to go in texture atlas too 2011-12-01 14:12:47 +02:00
Perttu Ahola
e6e3eef0ef Add ServerActiveObject::removingFromEnvironment() 2011-12-01 13:22:33 +02:00
Perttu Ahola
0e113a4c81 Remove +"^[forcesingle" from ContentFeatures::setInventoryTexture, because 1) it was not used, 2) if it will be used, it won't need to do that anymore 2011-12-01 13:01:37 +02:00
Perttu Ahola
1da3a8e24b Fix getTextureRaw to always return an image that is not in the texture atlas and fix plain "^[forcesingle" handling 2011-12-01 13:00:27 +02:00
Perttu Ahola
3509714951 Fix loading of legacy MaterialItems (was loaded as a quite random type) 2011-12-01 12:50:32 +02:00
Perttu Ahola
146be1f0b6 Fix texture atlas not being created correctly 2011-12-01 12:43:17 +02:00
Perttu Ahola
223a4f4741 Include the freedesktop.org-standard .desktop file in misc/ to aid package makers 2011-12-01 12:12:48 +02:00
Perttu Ahola
1f1c1790f5 Remove old stuff from misc/ 2011-12-01 12:11:26 +02:00
Kahrl
2ca00fa585 Fix processing of the default_password setting. It is now actually used as the plaintext password for new users. Also add /setpassword and /clearpassword server commands that can be used by admins with the PRIV_PASSWORD privilege, and update the /help message. 2011-12-01 12:06:39 +02:00
Kahrl
1901158b3e Make camera.cpp Irrlicht 1.8-compatible by calling ITexture::lock differently depending on the irrlicht version. 2011-12-01 11:56:06 +02:00
Kahrl
63d3403a20 Wireshark dissector: correct messed up field names 2011-12-01 11:38:06 +02:00
Kahrl
7f7fe444d3 Wireshark dissector: Add TOSERVER_RESPAWN and TOCLIENT_DEATHSCREEN, plus some failed assertion fix (well, hack). 2011-12-01 11:38:06 +02:00
Perttu Ahola
f4272ccf8f Enable simple drag and drop in inventory 2011-12-01 11:32:51 +02:00
Perttu Ahola
4196b0d341 Inventory move-to-slot hilighting 2011-12-01 11:25:55 +02:00
Perttu Ahola
ebc7a36a83 Note in init.lua the methods specific to the "generic" node metadata 2011-12-01 10:55:25 +02:00
Giuseppe Bilotta
aab50cd2cc Fix conditional bug in inventory
A spurious semicolon after the conditional checking for the drop count
to be not higher than the owned count caused the subsequent
    count = getCount()
to be always executed. Fix by removing the extra semicolon.
2011-12-01 10:41:24 +02:00
Giuseppe Bilotta
96c30452f9 Fix structs being declared as classes
Some compilers complain when a class is declared as a struct or vice
versa. Fix by making sure that the correct tag is used both in
declaration and definition.
2011-12-01 10:39:47 +02:00
Perttu Ahola
4d0f227c70 Fix sand to be cookable to glass 2011-12-01 02:56:49 +02:00
Perttu Ahola
50b87c3791 Update version in CMakeLists.txt to 0.4.dev-20111201-1 2011-12-01 02:43:10 +02:00
Perttu Ahola
b6539399f4 Fix deadlock if MeshUpdateThread asks new textures while it is being stopped (happened if texture data was transferred slowly) 2011-12-01 02:41:52 +02:00
Perttu Ahola
8b8ef8acc0 Move NodeMetadata prototype containers to content_nodemeta.cpp to fix them not being filled correctly on some systems and compilers 2011-12-01 01:58:31 +02:00
66 changed files with 3515 additions and 9757 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-20111201-0)
set(VERSION_PATCH dev-20111203-3)
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
MESSAGE(STATUS "*** Will build version ${VERSION_STRING} ***")

View File

@@ -195,16 +195,17 @@ cmake %sourcedir% -G "Visual Studio 10" -DIRRLICHT_SOURCE_DIR=%irrlichtpath% -DR
"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" PACKAGE.vcxproj /p:Configuration=Release
popd
License of Minetest-c55 textures
--------------------------------
License of Minetest-c55 textures and sounds
-------------------------------------------
This does not apply to texture packs made by others.
This applies to textures and sounds contained in the main Minetest
distribution.
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
http://creativecommons.org/licenses/by-sa/3.0/
License of Minetest-c55
-----------------------
License of Minetest-c55 source code
-----------------------------------
Minetest-c55
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>

View File

@@ -156,9 +156,9 @@ minetest.register_node("ignore", {
--
-- stackstring manipulation functions
-- example stackstring: 'CraftItem "apple" 4'
-- example item: {type="CraftItem", name="apple"}
-- example item: {type="ToolItem", name="SteelPick", wear="23272"}
-- example stackstring: 'craft "apple" 4'
-- example item: {type="craft", name="apple"}
-- example item: {type="tool", name="SteelPick", wear="23272"}
--
function stackstring_take_item(stackstring)
@@ -167,13 +167,13 @@ function stackstring_take_item(stackstring)
end
local stacktype = nil
stacktype = string.match(stackstring,
'([%a%d]+Item[%a%d]*)')
if stacktype == "NodeItem" or stacktype == "CraftItem" then
'([%a%d]+)')
if stacktype == "node" or stacktype == "craft" then
local itemtype = nil
local itemname = nil
local itemcount = nil
itemtype, itemname, itemcount = string.match(stackstring,
'([%a%d]+Item[%a%d]*) "([^"]*)" (%d+)')
'([%a%d]+) "([^"]*)" (%d+)')
itemcount = tonumber(itemcount)
if itemcount == 0 then
return '', nil
@@ -183,12 +183,12 @@ function stackstring_take_item(stackstring)
return itemtype.." \""..itemname.."\" "..(itemcount-1),
{type=itemtype, name=itemname}
end
elseif stacktype == "ToolItem" then
elseif stacktype == "tool" then
local itemtype = nil
local itemname = nil
local itemwear = nil
itemtype, itemname, itemwear = string.match(stackstring,
'([%a%d]+Item[%a%d]*) "([^"]*)" (%d+)')
'([%a%d]+) "([^"]*)" (%d+)')
itemwear = tonumber(itemwear)
return '', {type=itemtype, name=itemname, wear=itemwear}
end
@@ -201,17 +201,17 @@ function stackstring_put_item(stackstring, item)
stackstring = stackstring or ''
local stacktype = nil
stacktype = string.match(stackstring,
'([%a%d]+Item[%a%d]*)')
'([%a%d]+)')
stacktype = stacktype or ''
if stacktype ~= '' and stacktype ~= item.type then
return stackstring, false
end
if item.type == "NodeItem" or item.type == "CraftItem" then
if item.type == "node" or item.type == "craft" then
local itemtype = nil
local itemname = nil
local itemcount = nil
itemtype, itemname, itemcount = string.match(stackstring,
'([%a%d]+Item[%a%d]*) "([^"]*)" (%d+)')
'([%a%d]+) "([^"]*)" (%d+)')
itemtype = itemtype or item.type
itemname = itemname or item.name
if itemcount == nil then
@@ -219,7 +219,7 @@ function stackstring_put_item(stackstring, item)
end
itemcount = itemcount + 1
return itemtype.." \""..itemname.."\" "..itemcount, true
elseif item.type == "ToolItem" then
elseif item.type == "tool" then
if stacktype ~= nil then
return stackstring, false
end
@@ -227,7 +227,7 @@ function stackstring_put_item(stackstring, item)
local itemname = nil
local itemwear = nil
itemtype, itemname, itemwear = string.match(stackstring,
'([%a%d]+Item[%a%d]*) "([^"]*)" (%d+)')
'([%a%d]+) "([^"]*)" (%d+)')
itemwear = tonumber(itemwear)
return itemtype.." \""..itemname.."\" "..itemwear, true
end
@@ -253,56 +253,69 @@ function test_stackstring()
local item
local success
stack, item = stackstring_take_item('NodeItem "TNT" 3')
assert(stack == 'NodeItem "TNT" 2')
assert(item.type == 'NodeItem')
stack, item = stackstring_take_item('node "TNT" 3')
assert(stack == 'node "TNT" 2')
assert(item.type == 'node')
assert(item.name == 'TNT')
stack, item = stackstring_take_item('CraftItem "with spaces" 2')
assert(stack == 'CraftItem "with spaces" 1')
assert(item.type == 'CraftItem')
stack, item = stackstring_take_item('craft "with spaces" 2')
assert(stack == 'craft "with spaces" 1')
assert(item.type == 'craft')
assert(item.name == 'with spaces')
stack, item = stackstring_take_item('CraftItem "with spaces" 1')
stack, item = stackstring_take_item('craft "with spaces" 1')
assert(stack == '')
assert(item.type == 'CraftItem')
assert(item.type == 'craft')
assert(item.name == 'with spaces')
stack, item = stackstring_take_item('CraftItem "s8df2kj3" 0')
stack, item = stackstring_take_item('craft "s8df2kj3" 0')
assert(stack == '')
assert(item == nil)
stack, item = stackstring_take_item('ToolItem "With Spaces" 32487')
stack, item = stackstring_take_item('tool "With Spaces" 32487')
assert(stack == '')
assert(item.type == 'ToolItem')
assert(item.type == 'tool')
assert(item.name == 'With Spaces')
assert(item.wear == 32487)
stack, success = stackstring_put_item('NodeItem "With Spaces" 40',
{type='NodeItem', name='With Spaces'})
assert(stack == 'NodeItem "With Spaces" 41')
stack, success = stackstring_put_item('node "With Spaces" 40',
{type='node', name='With Spaces'})
assert(stack == 'node "With Spaces" 41')
assert(success == true)
stack, success = stackstring_put_item('CraftItem "With Spaces" 40',
{type='CraftItem', name='With Spaces'})
assert(stack == 'CraftItem "With Spaces" 41')
stack, success = stackstring_put_item('craft "With Spaces" 40',
{type='craft', name='With Spaces'})
assert(stack == 'craft "With Spaces" 41')
assert(success == true)
stack, success = stackstring_put_item('ToolItem "With Spaces" 32487',
{type='ToolItem', name='With Spaces'})
assert(stack == 'ToolItem "With Spaces" 32487')
stack, success = stackstring_put_item('tool "With Spaces" 32487',
{type='tool', name='With Spaces'})
assert(stack == 'tool "With Spaces" 32487')
assert(success == false)
stack, success = stackstring_put_item('NodeItem "With Spaces" 40',
{type='ToolItem', name='With Spaces'})
assert(stack == 'NodeItem "With Spaces" 40')
stack, success = stackstring_put_item('node "With Spaces" 40',
{type='tool', name='With Spaces'})
assert(stack == 'node "With Spaces" 40')
assert(success == false)
assert(stackstring_put_stackstring('NodeItem "With Spaces" 2',
'NodeItem "With Spaces" 1') == 'NodeItem "With Spaces" 3')
assert(stackstring_put_stackstring('node "With Spaces" 2',
'node "With Spaces" 1') == 'node "With Spaces" 3')
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
--
@@ -312,7 +325,7 @@ minetest.craftitem_place_item = function(item, placer, pos)
--print("item: " .. dump(item))
--print("placer: " .. dump(placer))
--print("pos: " .. dump(pos))
minetest.env:add_item(pos, 'CraftItem "' .. item .. '" 1')
minetest.env:add_item(pos, 'craft "' .. item .. '" 1')
return true
end
@@ -327,6 +340,16 @@ minetest.craftitem_eat = function(hp_change)
end
end
--
-- Creative inventory
--
minetest.creative_inventory = {}
minetest.add_to_creative_inventory = function(itemstring)
table.insert(minetest.creative_inventory, itemstring)
end
--
-- Callback registration
--

View File

@@ -1,12 +1,12 @@
minetest.register_craft({
output = 'CraftItem "bucket" 1',
output = 'craft "bucket:bucket_empty" 1',
recipe = {
{'CraftItem "steel_ingot"', '', 'CraftItem "steel_ingot"'},
{'', 'CraftItem "steel_ingot"', ''},
{'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('CraftItem "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('CraftItem "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('CraftItem "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('CraftItem "bucket" 1')
player:add_to_inventory_later('craft "bucket:bucket_empty" 1')
return true
end
return false

File diff suppressed because it is too large Load Diff

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)
@@ -56,7 +56,7 @@ minetest.register_abm({
_, srcitem = stackstring_take_item(srclist[1])
_, fuelitem = stackstring_take_item(fuellist[1])
if not srcitem or not fuelitem then return end
if fuelitem.type == "NodeItem" then
if fuelitem.type == "node" then
local prop = minetest.registered_nodes[fuelitem.name]
if prop == nil then return end
if prop.furnace_burntime < 0 then return end
@@ -64,7 +64,7 @@ minetest.register_abm({
return
end
local resultstack = nil
if srcitem.type == "NodeItem" then
if srcitem.type == "node" then
local prop = minetest.registered_nodes[srcitem.name]
if prop == nil then return end
if prop.cookresult_item == "" then return end
@@ -97,11 +97,11 @@ minetest.register_abm({
})
minetest.register_craft({
output = 'NodeItem "luafurnace" 1',
output = 'node "experimental:luafurnace" 1',
recipe = {
{'NodeItem "cobble"', 'NodeItem "cobble"', 'NodeItem "cobble"'},
{'NodeItem "cobble"', 'NodeItem "cobble"', 'NodeItem "cobble"'},
{'NodeItem "cobble"', 'NodeItem "cobble"', 'NodeItem "cobble"'},
{'node "cobble"', 'node "cobble"', 'node "cobble"'},
{'node "cobble"', 'node "cobble"', 'node "cobble"'},
{'node "cobble"', 'node "cobble"', 'node "cobble"'},
}
})
@@ -126,15 +126,16 @@ minetest.register_tool("horribletool", {
--]]
minetest.register_craft({
output = 'NodeItem "somenode" 4',
output = 'node "somenode" 4',
recipe = {
{'CraftItem "Stick" 1'},
{'craft "Stick" 1'},
}
})
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,15 +152,15 @@ minetest.register_node("somenode", {
--
minetest.register_craft({
output = 'NodeItem "TNT" 4',
output = 'node "experimental:tnt" 4',
recipe = {
{'NodeItem "wood" 1'},
{'CraftItem "lump_of_coal" 1'},
{'NodeItem "wood" 1'}
{'node "wood" 1'},
{'craft "lump_of_coal" 1'},
{'node "wood" 1'}
}
})
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
@@ -213,7 +222,7 @@ function TNT:on_punch(hitter)
self.health = self.health - 1
if self.health <= 0 then
self.object:remove()
hitter:add_to_inventory("NodeItem TNT 1")
hitter:add_to_inventory("node TNT 1")
hitter:set_hp(hitter:get_hp() - 1)
end
end
@@ -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,
@@ -259,7 +267,7 @@ minetest.register_entity("testentity", {
on_punch = function(self, hitter)
self.object:remove()
hitter:add_to_inventory('CraftItem testobject1 1')
hitter:add_to_inventory('craft testobject1 1')
end,
})

View File

@@ -2,11 +2,11 @@ minetest.register_on_newplayer(function(player)
print("on_newplayer")
if minetest.setting_getbool("give_initial_stuff") then
print("giving give_initial_stuff to player")
player:add_to_inventory('ToolItem "SteelPick" 0')
player:add_to_inventory('NodeItem "torch" 99')
player:add_to_inventory('ToolItem "SteelAxe" 0')
player:add_to_inventory('ToolItem "SteelShovel" 0')
player:add_to_inventory('NodeItem "cobble" 99')
player:add_to_inventory('tool "SteelPick" 0')
player:add_to_inventory('node "torch" 99')
player:add_to_inventory('tool "SteelAxe" 0')
player:add_to_inventory('tool "SteelShovel" 0')
player:add_to_inventory('node "cobble" 99')
end
end)

View File

@@ -131,12 +131,14 @@
#default_password =
# Available privileges: build, teleport, settime, privs, shout
#default_privs = build, shout
# Whether players are transferred to client without any range limit
#unlimited_player_transfer_distance = true
# Whether to enable players killing each other
#enable_pvp = true
# Profiler data print interval. #0 = disable.
#profiler_print_interval = 0
#enable_mapgen_debug_info = false
# Player and object positions are sent at intervals specified by this
#objectdata_interval = 0.2
#active_object_send_range_blocks = 3
#active_block_range = 2
#max_simultaneous_block_sends_per_client = 2
@@ -146,8 +148,8 @@
#time_send_interval = 20
# Length of day/night cycle. 72=20min, 360=4min, 1=24hour
#time_speed = 72
#server_unload_unused_data_timeout = 60
#server_map_save_interval = 60
#server_unload_unused_data_timeout = 29
#server_map_save_interval = 5.3
#full_block_send_enable_min_time_from_building = 2.0
# Set to true to enable experimental features or stuff that is tested
# (varies from version to version, usually not useful at all)

File diff suppressed because it is too large Load Diff

11
misc/minetest.desktop Normal file
View File

@@ -0,0 +1,11 @@
[Desktop Entry]
Name=Minetest
GenericName=Minetest
Comment=Multiplayer infinite-world block sandbox
Exec=minetest
Icon=minetest-icon
Terminal=false
Type=Application
Categories=Game;
StartupNotify=false

View File

@@ -1,410 +0,0 @@
/*
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 <math.h>
#include "noise.h"
#include <iostream>
#include "debug.h"
#define NOISE_MAGIC_X 1619
#define NOISE_MAGIC_Y 31337
#define NOISE_MAGIC_Z 52591
#define NOISE_MAGIC_SEED 1013
double cos_lookup[16] = {
1.0,0.9238,0.7071,0.3826,0,-0.3826,-0.7071,-0.9238,
1.0,-0.9238,-0.7071,-0.3826,0,0.3826,0.7071,0.9238
};
double dotProduct(double vx, double vy, double wx, double wy){
return vx*wx+vy*wy;
}
double easeCurve(double t){
return 6*pow(t,5)-15*pow(t,4)+10*pow(t,3);
}
double linearInterpolation(double x0, double x1, double t){
return x0+(x1-x0)*t;
}
double biLinearInterpolation(double x0y0, double x1y0, double x0y1, double x1y1, double x, double y){
double tx = easeCurve(x);
double ty = easeCurve(y);
/*double tx = x;
double ty = y;*/
double u = linearInterpolation(x0y0,x1y0,tx);
double v = linearInterpolation(x0y1,x1y1,tx);
return linearInterpolation(u,v,ty);
}
double triLinearInterpolation(
double v000, double v100, double v010, double v110,
double v001, double v101, double v011, double v111,
double x, double y, double z)
{
/*double tx = easeCurve(x);
double ty = easeCurve(y);
double tz = easeCurve(z);*/
double tx = x;
double ty = y;
double tz = z;
return(
v000*(1-tx)*(1-ty)*(1-tz) +
v100*tx*(1-ty)*(1-tz) +
v010*(1-tx)*ty*(1-tz) +
v110*tx*ty*(1-tz) +
v001*(1-tx)*(1-ty)*tz +
v101*tx*(1-ty)*tz +
v011*(1-tx)*ty*tz +
v111*tx*ty*tz
);
}
double noise2d(int x, int y, int seed)
{
int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y
+ NOISE_MAGIC_SEED * seed) & 0x7fffffff;
n = (n>>13)^n;
n = (n * (n*n*60493+19990303) + 1376312589) & 0x7fffffff;
return 1.0 - (double)n/1073741824;
}
double noise3d(int x, int y, int z, int seed)
{
int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_Z * z
+ NOISE_MAGIC_SEED * seed) & 0x7fffffff;
n = (n>>13)^n;
n = (n * (n*n*60493+19990303) + 1376312589) & 0x7fffffff;
return 1.0 - (double)n/1073741824;
}
#if 0
double noise2d_gradient(double x, double y, int seed)
{
// Calculate the integer coordinates
int x0 = (x > 0.0 ? (int)x : (int)x - 1);
int y0 = (y > 0.0 ? (int)y : (int)y - 1);
// Calculate the remaining part of the coordinates
double xl = x - (double)x0;
double yl = y - (double)y0;
// Calculate random cosine lookup table indices for the integer corners.
// They are looked up as unit vector gradients from the lookup table.
int n00 = (int)((noise2d(x0, y0, seed)+1)*8);
int n10 = (int)((noise2d(x0+1, y0, seed)+1)*8);
int n01 = (int)((noise2d(x0, y0+1, seed)+1)*8);
int n11 = (int)((noise2d(x0+1, y0+1, seed)+1)*8);
// Make a dot product for the gradients and the positions, to get the values
double s = dotProduct(cos_lookup[n00], cos_lookup[(n00+12)%16], xl, yl);
double u = dotProduct(-cos_lookup[n10], cos_lookup[(n10+12)%16], 1.-xl, yl);
double v = dotProduct(cos_lookup[n01], -cos_lookup[(n01+12)%16], xl, 1.-yl);
double w = dotProduct(-cos_lookup[n11], -cos_lookup[(n11+12)%16], 1.-xl, 1.-yl);
// Interpolate between the values
return biLinearInterpolation(s,u,v,w,xl,yl);
}
#endif
#if 1
double noise2d_gradient(double x, double y, int seed)
{
// Calculate the integer coordinates
int x0 = (x > 0.0 ? (int)x : (int)x - 1);
int y0 = (y > 0.0 ? (int)y : (int)y - 1);
// Calculate the remaining part of the coordinates
double xl = x - (double)x0;
double yl = y - (double)y0;
// Get values for corners of cube
double v00 = noise2d(x0, y0, seed);
double v10 = noise2d(x0+1, y0, seed);
double v01 = noise2d(x0, y0+1, seed);
double v11 = noise2d(x0+1, y0+1, seed);
// Interpolate
return biLinearInterpolation(v00,v10,v01,v11,xl,yl);
}
#endif
double noise3d_gradient(double x, double y, double z, int seed)
{
// Calculate the integer coordinates
int x0 = (x > 0.0 ? (int)x : (int)x - 1);
int y0 = (y > 0.0 ? (int)y : (int)y - 1);
int z0 = (z > 0.0 ? (int)z : (int)z - 1);
// Calculate the remaining part of the coordinates
double xl = x - (double)x0;
double yl = y - (double)y0;
double zl = z - (double)z0;
// Get values for corners of cube
double v000 = noise3d(x0, y0, z0, seed);
double v100 = noise3d(x0+1, y0, z0, seed);
double v010 = noise3d(x0, y0+1, z0, seed);
double v110 = noise3d(x0+1, y0+1, z0, seed);
double v001 = noise3d(x0, y0, z0+1, seed);
double v101 = noise3d(x0+1, y0, z0+1, seed);
double v011 = noise3d(x0, y0+1, z0+1, seed);
double v111 = noise3d(x0+1, y0+1, z0+1, seed);
// Interpolate
return triLinearInterpolation(v000,v100,v010,v110,v001,v101,v011,v111,xl,yl,zl);
}
double noise2d_perlin(double x, double y, int seed,
int octaves, double persistence)
{
double a = 0;
double f = 1.0;
double g = 1.0;
for(int i=0; i<octaves; i++)
{
a += g * noise2d_gradient(x*f, y*f, seed+i);
f *= 2.0;
g *= persistence;
}
return a;
}
double noise2d_perlin_abs(double x, double y, int seed,
int octaves, double persistence)
{
double a = 0;
double f = 1.0;
double g = 1.0;
for(int i=0; i<octaves; i++)
{
a += g * fabs(noise2d_gradient(x*f, y*f, seed+i));
f *= 2.0;
g *= persistence;
}
return a;
}
double noise3d_perlin(double x, double y, double z, int seed,
int octaves, double persistence)
{
double a = 0;
double f = 1.0;
double g = 1.0;
for(int i=0; i<octaves; i++)
{
a += g * noise3d_gradient(x*f, y*f, z*f, seed+i);
f *= 2.0;
g *= persistence;
}
return a;
}
double noise3d_perlin_abs(double x, double y, double z, int seed,
int octaves, double persistence)
{
double a = 0;
double f = 1.0;
double g = 1.0;
for(int i=0; i<octaves; i++)
{
a += g * fabs(noise3d_gradient(x*f, y*f, z*f, seed+i));
f *= 2.0;
g *= persistence;
}
return a;
}
// -1->0, 0->1, 1->0
double contour(double v)
{
v = fabs(v);
if(v >= 1.0)
return 0.0;
return (1.0-v);
}
double noise3d_param(const NoiseParams &param, double x, double y, double z)
{
double s = param.pos_scale;
x /= s;
y /= s;
z /= s;
if(param.type == NOISE_PERLIN)
{
return param.noise_scale*noise3d_perlin(x,y,z, param.seed,
param.octaves,
param.persistence);
}
else if(param.type == NOISE_PERLIN_ABS)
{
return param.noise_scale*noise3d_perlin_abs(x,y,z, param.seed,
param.octaves,
param.persistence);
}
else if(param.type == NOISE_PERLIN_CONTOUR)
{
return contour(param.noise_scale*noise3d_perlin(x,y,z,
param.seed, param.octaves,
param.persistence));
}
else if(param.type == NOISE_PERLIN_CONTOUR_FLIP_YZ)
{
return contour(param.noise_scale*noise3d_perlin(x,z,y,
param.seed, param.octaves,
param.persistence));
}
else assert(0);
}
/*
NoiseBuffer
*/
NoiseBuffer::NoiseBuffer():
m_data(NULL)
{
}
NoiseBuffer::~NoiseBuffer()
{
clear();
}
void NoiseBuffer::clear()
{
if(m_data)
delete[] m_data;
m_data = NULL;
m_size_x = 0;
m_size_y = 0;
m_size_z = 0;
}
void NoiseBuffer::create(const NoiseParams &param,
double first_x, double first_y, double first_z,
double last_x, double last_y, double last_z,
double samplelength_x, double samplelength_y, double samplelength_z)
{
clear();
m_start_x = first_x - samplelength_x;
m_start_y = first_y - samplelength_y;
m_start_z = first_z - samplelength_z;
m_samplelength_x = samplelength_x;
m_samplelength_y = samplelength_y;
m_samplelength_z = samplelength_z;
m_size_x = (last_x - m_start_x)/samplelength_x + 2;
m_size_y = (last_y - m_start_y)/samplelength_y + 2;
m_size_z = (last_z - m_start_z)/samplelength_z + 2;
m_data = new double[m_size_x*m_size_y*m_size_z];
for(int x=0; x<m_size_x; x++)
for(int y=0; y<m_size_y; y++)
for(int z=0; z<m_size_z; z++)
{
double xd = (m_start_x + (double)x*m_samplelength_x);
double yd = (m_start_y + (double)y*m_samplelength_y);
double zd = (m_start_z + (double)z*m_samplelength_z);
double a = noise3d_param(param, xd,yd,zd);
intSet(x,y,z, a);
}
}
void NoiseBuffer::multiply(const NoiseParams &param)
{
assert(m_data != NULL);
for(int x=0; x<m_size_x; x++)
for(int y=0; y<m_size_y; y++)
for(int z=0; z<m_size_z; z++)
{
double xd = (m_start_x + (double)x*m_samplelength_x);
double yd = (m_start_y + (double)y*m_samplelength_y);
double zd = (m_start_z + (double)z*m_samplelength_z);
double a = noise3d_param(param, xd,yd,zd);
intMultiply(x,y,z, a);
}
}
// Deprecated
void NoiseBuffer::create(int seed, int octaves, double persistence,
bool abs,
double first_x, double first_y, double first_z,
double last_x, double last_y, double last_z,
double samplelength_x, double samplelength_y, double samplelength_z)
{
NoiseParams param;
param.type = abs ? NOISE_PERLIN_ABS : NOISE_PERLIN;
param.seed = seed;
param.octaves = octaves;
param.persistence = persistence;
create(param, first_x, first_y, first_z,
last_x, last_y, last_z,
samplelength_x, samplelength_y, samplelength_z);
}
void NoiseBuffer::intSet(int x, int y, int z, double d)
{
int i = m_size_x*m_size_y*z + m_size_x*y + x;
assert(i >= 0);
assert(i < m_size_x*m_size_y*m_size_z);
m_data[i] = d;
}
void NoiseBuffer::intMultiply(int x, int y, int z, double d)
{
int i = m_size_x*m_size_y*z + m_size_x*y + x;
assert(i >= 0);
assert(i < m_size_x*m_size_y*m_size_z);
m_data[i] = m_data[i] * d;
}
double NoiseBuffer::intGet(int x, int y, int z)
{
int i = m_size_x*m_size_y*z + m_size_x*y + x;
assert(i >= 0);
assert(i < m_size_x*m_size_y*m_size_z);
return m_data[i];
}
double NoiseBuffer::get(double x, double y, double z)
{
x -= m_start_x;
y -= m_start_y;
z -= m_start_z;
x /= m_samplelength_x;
y /= m_samplelength_y;
z /= m_samplelength_z;
// Calculate the integer coordinates
int x0 = (x > 0.0 ? (int)x : (int)x - 1);
int y0 = (y > 0.0 ? (int)y : (int)y - 1);
int z0 = (z > 0.0 ? (int)z : (int)z - 1);
// Calculate the remaining part of the coordinates
double xl = x - (double)x0;
double yl = y - (double)y0;
double zl = z - (double)z0;
// Get values for corners of cube
double v000 = intGet(x0, y0, z0);
double v100 = intGet(x0+1, y0, z0);
double v010 = intGet(x0, y0+1, z0);
double v110 = intGet(x0+1, y0+1, z0);
double v001 = intGet(x0, y0, z0+1);
double v101 = intGet(x0+1, y0, z0+1);
double v011 = intGet(x0, y0+1, z0+1);
double v111 = intGet(x0+1, y0+1, z0+1);
// Interpolate
return triLinearInterpolation(v000,v100,v010,v110,v001,v101,v011,v111,xl,yl,zl);
}

View File

@@ -1,108 +0,0 @@
/*
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 NOISE_HEADER
#define NOISE_HEADER
double easeCurve(double t);
// Return value: -1 ... 1
double noise2d(int x, int y, int seed);
double noise3d(int x, int y, int z, int seed);
double noise2d_gradient(double x, double y, int seed);
double noise3d_gradient(double x, double y, double z, int seed);
double noise2d_perlin(double x, double y, int seed,
int octaves, double persistence);
double noise2d_perlin_abs(double x, double y, int seed,
int octaves, double persistence);
double noise3d_perlin(double x, double y, double z, int seed,
int octaves, double persistence);
double noise3d_perlin_abs(double x, double y, double z, int seed,
int octaves, double persistence);
enum NoiseType
{
NOISE_PERLIN,
NOISE_PERLIN_ABS,
NOISE_PERLIN_CONTOUR,
NOISE_PERLIN_CONTOUR_FLIP_YZ
};
struct NoiseParams
{
NoiseType type;
int seed;
int octaves;
double persistence;
double pos_scale;
double noise_scale; // Useful for contour noises
NoiseParams(NoiseType type_=NOISE_PERLIN, int seed_=0,
int octaves_=3, double persistence_=0.5,
double pos_scale_=100.0, double noise_scale_=1.0):
type(type_),
seed(seed_),
octaves(octaves_),
persistence(persistence_),
pos_scale(pos_scale_),
noise_scale(noise_scale_)
{
}
};
double noise3d_param(const NoiseParams &param, double x, double y, double z);
class NoiseBuffer
{
public:
NoiseBuffer();
~NoiseBuffer();
void clear();
void create(const NoiseParams &param,
double first_x, double first_y, double first_z,
double last_x, double last_y, double last_z,
double samplelength_x, double samplelength_y, double samplelength_z);
void multiply(const NoiseParams &param);
// Deprecated
void create(int seed, int octaves, double persistence,
bool abs,
double first_x, double first_y, double first_z,
double last_x, double last_y, double last_z,
double samplelength_x, double samplelength_y, double samplelength_z);
void intSet(int x, int y, int z, double d);
void intMultiply(int x, int y, int z, double d);
double intGet(int x, int y, int z);
double get(double x, double y, double z);
private:
double *m_data;
double m_start_x, m_start_y, m_start_z;
double m_samplelength_x, m_samplelength_y, m_samplelength_z;
int m_size_x, m_size_y, m_size_z;
};
#endif

View File

@@ -94,6 +94,8 @@ configure_file(
)
set(common_SRCS
mods.cpp
serverremoteplayer.cpp
content_abm.cpp
craftdef.cpp
nameidmapping.cpp
@@ -107,7 +109,6 @@ set(common_SRCS
content_sao.cpp
mapgen.cpp
content_nodemeta.cpp
content_craft.cpp
content_mapnode.cpp
auth.cpp
collision.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

@@ -28,8 +28,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
std::set<std::string> privsToSet(u64 privs)
{
std::set<std::string> s;
if(privs & PRIV_BUILD)
s.insert("build");
if(privs & PRIV_INTERACT)
s.insert("interact");
if(privs & PRIV_TELEPORT)
s.insert("teleport");
if(privs & PRIV_SETTIME)
@@ -42,6 +42,8 @@ std::set<std::string> privsToSet(u64 privs)
s.insert("ban");
if(privs & PRIV_GIVE)
s.insert("give");
if(privs & PRIV_PASSWORD)
s.insert("password");
return s;
}
@@ -50,8 +52,8 @@ std::set<std::string> privsToSet(u64 privs)
std::string privsToString(u64 privs)
{
std::ostringstream os(std::ios_base::binary);
if(privs & PRIV_BUILD)
os<<"build,";
if(privs & PRIV_INTERACT)
os<<"interact,";
if(privs & PRIV_TELEPORT)
os<<"teleport,";
if(privs & PRIV_SETTIME)
@@ -64,6 +66,8 @@ std::string privsToString(u64 privs)
os<<"ban,";
if(privs & PRIV_GIVE)
os<<"give,";
if(privs & PRIV_PASSWORD)
os<<"password,";
if(os.tellp())
{
// Drop the trailing comma. (Why on earth can't
@@ -85,7 +89,9 @@ u64 stringToPrivs(std::string str)
{
std::string s = trim(f.next(","));
if(s == "build")
privs |= PRIV_BUILD;
privs |= PRIV_INTERACT;
else if(s == "interact")
privs |= PRIV_INTERACT;
else if(s == "teleport")
privs |= PRIV_TELEPORT;
else if(s == "settime")
@@ -98,6 +104,8 @@ u64 stringToPrivs(std::string str)
privs |= PRIV_BAN;
else if(s == "give")
privs |= PRIV_GIVE;
else if(s == "password")
privs |= PRIV_PASSWORD;
else
return PRIV_INVALID;
}

View File

@@ -31,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// of the player, and define things they're allowed to do. See also
// the static methods Player::privsToString and stringToPrivs that
// convert these to human-readable form.
const u64 PRIV_BUILD = 1; // Can build - i.e. modify the world
const u64 PRIV_INTERACT = 1; // Can interact
const u64 PRIV_TELEPORT = 2; // Can teleport
const u64 PRIV_SETTIME = 4; // Can set the time
const u64 PRIV_PRIVS = 8; // Can grant and revoke privileges
@@ -41,11 +41,12 @@ const u64 PRIV_SHOUT = 32; // Can broadcast chat messages to all
// players
const u64 PRIV_BAN = 64; // Can ban players
const u64 PRIV_GIVE = 128; // Can give stuff
const u64 PRIV_PASSWORD = 256; // Can set other players' passwords
// Default privileges - these can be overriden for new players using the
// config option "default_privs" - however, this value still applies for
// players that existed before the privileges system was added.
const u64 PRIV_DEFAULT = PRIV_BUILD|PRIV_SHOUT;
const u64 PRIV_DEFAULT = PRIV_INTERACT|PRIV_SHOUT;
const u64 PRIV_ALL = 0x7FFFFFFFFFFFFFFFULL;
const u64 PRIV_INVALID = 0x8000000000000000ULL;

View File

@@ -22,10 +22,10 @@ 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
@@ -269,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;
@@ -472,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:
@@ -484,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);
@@ -492,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);
}
}
@@ -526,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;
@@ -541,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);
@@ -558,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;
@@ -570,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);
@@ -582,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
@@ -616,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)
@@ -627,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();
@@ -657,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(true);
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(true));
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>
@@ -29,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IAnimatedMesh.h>
class LocalPlayer;
class MapDrawControl;
struct MapDrawControl;
class ExtrudedSpriteSceneNode;
class IGameDef;
@@ -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

@@ -205,7 +205,7 @@ Client::Client(
device->getSceneManager()->getRootSceneNode(),
device->getSceneManager(), 666),
device->getSceneManager(),
tsrc, this
tsrc, this, device
),
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
m_device(device),
@@ -566,7 +566,9 @@ void Client::step(float dtime)
if(m_ignore_damage_timer <= 0)
{
u8 damage = event.player_damage.amount;
sendDamage(damage);
if(event.player_damage.send_to_server)
sendDamage(damage);
// Add to ClientEvent queue
ClientEvent event;
@@ -940,219 +942,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
//infostream<<"Adding mesh update task for received block"<<std::endl;
addUpdateMeshTaskWithEdge(p, true);
}
else if(command == TOCLIENT_PLAYERPOS)
{
infostream<<"Received deprecated TOCLIENT_PLAYERPOS"
<<std::endl;
/*u16 our_peer_id;
{
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
our_peer_id = m_con.GetPeerID();
}
// Cancel if we don't have a peer id
if(our_peer_id == PEER_ID_INEXISTENT){
infostream<<"TOCLIENT_PLAYERPOS cancelled: "
"we have no peer id"
<<std::endl;
return;
}*/
{ //envlock
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
u32 player_size = 2+12+12+4+4;
u32 player_count = (datasize-2) / player_size;
u32 start = 2;
for(u32 i=0; i<player_count; i++)
{
u16 peer_id = readU16(&data[start]);
Player *player = m_env.getPlayer(peer_id);
// Skip if player doesn't exist
if(player == NULL)
{
start += player_size;
continue;
}
// Skip if player is local player
if(player->isLocal())
{
start += player_size;
continue;
}
v3s32 ps = readV3S32(&data[start+2]);
v3s32 ss = readV3S32(&data[start+2+12]);
s32 pitch_i = readS32(&data[start+2+12+12]);
s32 yaw_i = readS32(&data[start+2+12+12+4]);
/*infostream<<"Client: got "
<<"pitch_i="<<pitch_i
<<" yaw_i="<<yaw_i<<std::endl;*/
f32 pitch = (f32)pitch_i / 100.0;
f32 yaw = (f32)yaw_i / 100.0;
v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
player->setPosition(position);
player->setSpeed(speed);
player->setPitch(pitch);
player->setYaw(yaw);
/*infostream<<"Client: player "<<peer_id
<<" pitch="<<pitch
<<" yaw="<<yaw<<std::endl;*/
start += player_size;
}
} //envlock
}
else if(command == TOCLIENT_PLAYERINFO)
{
u16 our_peer_id;
{
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
our_peer_id = m_con.GetPeerID();
}
// Cancel if we don't have a peer id
if(our_peer_id == PEER_ID_INEXISTENT){
infostream<<"TOCLIENT_PLAYERINFO cancelled: "
"we have no peer id"
<<std::endl;
return;
}
//infostream<<"Client: Server reports players:"<<std::endl;
{ //envlock
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
u32 item_size = 2+PLAYERNAME_SIZE;
u32 player_count = (datasize-2) / item_size;
u32 start = 2;
// peer_ids
core::list<u16> players_alive;
for(u32 i=0; i<player_count; i++)
{
// Make sure the name ends in '\0'
data[start+2+20-1] = 0;
u16 peer_id = readU16(&data[start]);
players_alive.push_back(peer_id);
/*infostream<<"peer_id="<<peer_id
<<" name="<<((char*)&data[start+2])<<std::endl;*/
// Don't update the info of the local player
if(peer_id == our_peer_id)
{
start += item_size;
continue;
}
Player *player = m_env.getPlayer(peer_id);
// Create a player if it doesn't exist
if(player == NULL)
{
player = new RemotePlayer(this,
m_device->getSceneManager()->getRootSceneNode(),
m_device,
-1);
player->peer_id = peer_id;
m_env.addPlayer(player);
infostream<<"Client: Adding new player "
<<peer_id<<std::endl;
}
player->updateName((char*)&data[start+2]);
start += item_size;
}
/*
Remove those players from the environment that
weren't listed by the server.
*/
//infostream<<"Removing dead players"<<std::endl;
core::list<Player*> players = m_env.getPlayers();
core::list<Player*>::Iterator ip;
for(ip=players.begin(); ip!=players.end(); ip++)
{
// Ingore local player
if((*ip)->isLocal())
continue;
// Warn about a special case
if((*ip)->peer_id == 0)
{
infostream<<"Client: Removing "
"dead player with id=0"<<std::endl;
}
bool is_alive = false;
core::list<u16>::Iterator i;
for(i=players_alive.begin(); i!=players_alive.end(); i++)
{
if((*ip)->peer_id == *i)
{
is_alive = true;
break;
}
}
/*infostream<<"peer_id="<<((*ip)->peer_id)
<<" is_alive="<<is_alive<<std::endl;*/
if(is_alive)
continue;
infostream<<"Removing dead player "<<(*ip)->peer_id
<<std::endl;
m_env.removePlayer((*ip)->peer_id);
}
} //envlock
}
else if(command == TOCLIENT_SECTORMETA)
{
infostream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"<<std::endl;
#if 0
/*
[0] u16 command
[2] u8 sector count
[3...] v2s16 pos + sector metadata
*/
if(datasize < 3)
return;
//infostream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
{ //envlock
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
u8 buf[4];
is.read((char*)buf, 1);
u16 sector_count = readU8(buf);
//infostream<<"sector_count="<<sector_count<<std::endl;
for(u16 i=0; i<sector_count; i++)
{
// Read position
is.read((char*)buf, 4);
v2s16 pos = readV2S16(buf);
/*infostream<<"Client: deserializing sector at "
<<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
// Create sector
assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
}
} //envlock
#endif
}
else if(command == TOCLIENT_INVENTORY)
{
if(datasize < 3)
@@ -1187,73 +976,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
//player->inventory.print(infostream);
}
}
//DEBUG
else if(command == TOCLIENT_OBJECTDATA)
{
// Strip command word and create a stringstream
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
u8 buf[12];
/*
Read players
*/
is.read((char*)buf, 2);
u16 playercount = readU16(buf);
for(u16 i=0; i<playercount; i++)
{
is.read((char*)buf, 2);
u16 peer_id = readU16(buf);
is.read((char*)buf, 12);
v3s32 p_i = readV3S32(buf);
is.read((char*)buf, 12);
v3s32 s_i = readV3S32(buf);
is.read((char*)buf, 4);
s32 pitch_i = readS32(buf);
is.read((char*)buf, 4);
s32 yaw_i = readS32(buf);
Player *player = m_env.getPlayer(peer_id);
// Skip if player doesn't exist
if(player == NULL)
{
continue;
}
// Skip if player is local player
if(player->isLocal())
{
continue;
}
f32 pitch = (f32)pitch_i / 100.0;
f32 yaw = (f32)yaw_i / 100.0;
v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
player->setPosition(position);
player->setSpeed(speed);
player->setPitch(pitch);
player->setYaw(yaw);
}
/*
Read block objects
NOTE: Deprecated stuff
*/
// Read active block count
u16 blockcount = readU16(is);
if(blockcount != 0){
infostream<<"TOCLIENT_OBJECTDATA: blockcount != 0 "
"not supported"<<std::endl;
return;
}
}
else if(command == TOCLIENT_TIME_OF_DAY)
{
if(datasize < 4)
@@ -1519,7 +1241,12 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
std::istringstream is(datastring, std::ios_base::binary);
// Stop threads while updating content definitions
m_mesh_update_thread.stop();
m_mesh_update_thread.setRun(false);
// Process the remaining TextureSource queue to let MeshUpdateThread
// get it's remaining textures and thus let it stop
while(m_mesh_update_thread.IsRunning()){
m_tsrc->processQueue();
}
/*
u16 command
@@ -1595,8 +1322,13 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
m_tooldef_received = true;
// Stop threads while updating content definitions
m_mesh_update_thread.stop();
m_mesh_update_thread.setRun(false);
// Process the remaining TextureSource queue to let MeshUpdateThread
// get it's remaining textures and thus let it stop
while(m_mesh_update_thread.IsRunning()){
m_tsrc->processQueue();
}
std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
m_tooldef->deSerialize(tmp_is);
@@ -1644,8 +1376,13 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
m_craftitemdef_received = true;
// Stop threads while updating content definitions
m_mesh_update_thread.stop();
m_mesh_update_thread.setRun(false);
// Process the remaining TextureSource queue to let MeshUpdateThread
// get it's remaining textures and thus let it stop
while(m_mesh_update_thread.IsRunning()){
m_tsrc->processQueue();
}
std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
m_craftitemdef->deSerialize(tmp_is);

View File

@@ -26,9 +26,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
ClientActiveObject
*/
ClientActiveObject::ClientActiveObject(u16 id, IGameDef *gamedef):
ClientActiveObject::ClientActiveObject(u16 id, IGameDef *gamedef,
ClientEnvironment *env):
ActiveObject(id),
m_gamedef(gamedef)
m_gamedef(gamedef),
m_env(env)
{
}
@@ -37,7 +39,8 @@ ClientActiveObject::~ClientActiveObject()
removeFromScene();
}
ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef)
ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef,
ClientEnvironment *env)
{
// Find factory function
core::map<u16, Factory>::Node *n;
@@ -51,7 +54,7 @@ ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef)
}
Factory f = n->getValue();
ClientActiveObject *object = (*f)(gamedef);
ClientActiveObject *object = (*f)(gamedef, env);
return object;
}

View File

@@ -42,10 +42,11 @@ class IGameDef;
class ClientActiveObject : public ActiveObject
{
public:
ClientActiveObject(u16 id, IGameDef *gamedef);
ClientActiveObject(u16 id, IGameDef *gamedef, ClientEnvironment *env);
virtual ~ClientActiveObject();
virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc){}
virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr){}
virtual void removeFromScene(){}
// 0 <= light_at_pos <= LIGHT_SUN
virtual void updateLight(u8 light_at_pos){}
@@ -70,7 +71,8 @@ class ClientActiveObject : public ActiveObject
virtual void initialize(const std::string &data){}
// Create a certain type of ClientActiveObject
static ClientActiveObject* create(u8 type, IGameDef *gamedef);
static ClientActiveObject* create(u8 type, IGameDef *gamedef,
ClientEnvironment *env);
// If returns true, punch will not be sent to the server
virtual bool directReportPunch(const std::string &toolname, v3f dir)
@@ -78,9 +80,10 @@ class ClientActiveObject : public ActiveObject
protected:
// Used for creating objects based on type
typedef ClientActiveObject* (*Factory)(IGameDef *gamedef);
typedef ClientActiveObject* (*Factory)(IGameDef *gamedef, ClientEnvironment *env);
static void registerType(u16 type, Factory f);
IGameDef *m_gamedef;
ClientEnvironment *m_env;
private:
// Used for creating objects based on type
static core::map<u16, Factory> m_types;

View File

@@ -35,9 +35,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Add TOSERVER_INTERACT
Obsolete TOSERVER_CLICK_ACTIVEOBJECT
Obsolete TOSERVER_GROUND_ACTION
PROTOCOL_VERSION 5:
Make players to be handled mostly as ActiveObjects
*/
#define PROTOCOL_VERSION 4
#define PROTOCOL_VERSION 5
#define PROTOCOL_ID 0x4f457403
@@ -76,7 +78,7 @@ enum ToClientCommand
[N+2+12+12+4] s32 yaw*100
*/
TOCLIENT_PLAYERINFO = 0x24,
TOCLIENT_PLAYERINFO = 0x24, // Obsolete
/*
[0] u16 command
// Followed by an arbitary number of these:
@@ -100,7 +102,7 @@ enum ToClientCommand
[2] serialized inventory
*/
TOCLIENT_OBJECTDATA = 0x28,
TOCLIENT_OBJECTDATA = 0x28, // Obsolete
/*
Sent as unreliable.

View File

@@ -22,20 +22,394 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "environment.h"
#include "settings.h"
#include <ICameraSceneNode.h>
#include <ITextSceneNode.h>
#include "serialization.h" // For decompressZlib
#include "gamedef.h"
#include "clientobject.h"
#include "content_object.h"
#include "mesh.h"
#include "utility.h" // For IntervalLimiter
class Settings;
#include "MyBillboardSceneNode.h"
core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
/*
SmoothTranslator
*/
struct SmoothTranslator
{
v3f vect_old;
v3f vect_show;
v3f vect_aim;
f32 anim_counter;
f32 anim_time;
f32 anim_time_counter;
bool aim_is_end;
SmoothTranslator():
vect_old(0,0,0),
vect_show(0,0,0),
vect_aim(0,0,0),
anim_counter(0),
anim_time(0),
anim_time_counter(0),
aim_is_end(true)
{}
void init(v3f vect)
{
vect_old = vect;
vect_show = vect;
vect_aim = vect;
anim_counter = 0;
anim_time = 0;
anim_time_counter = 0;
aim_is_end = true;
}
void sharpen()
{
init(vect_show);
}
void update(v3f vect_new, bool is_end_position=false, float update_interval=-1)
{
aim_is_end = is_end_position;
vect_old = vect_show;
vect_aim = vect_new;
if(update_interval > 0){
anim_time = update_interval;
} else {
if(anim_time < 0.001 || anim_time > 1.0)
anim_time = anim_time_counter;
else
anim_time = anim_time * 0.9 + anim_time_counter * 0.1;
}
anim_time_counter = 0;
anim_counter = 0;
}
void translate(f32 dtime)
{
anim_time_counter = anim_time_counter + dtime;
anim_counter = anim_counter + dtime;
v3f vect_move = vect_aim - vect_old;
f32 moveratio = 1.0;
if(anim_time > 0.001)
moveratio = anim_time_counter / anim_time;
// Move a bit less than should, to avoid oscillation
moveratio = moveratio * 0.8;
float move_end = 1.5;
if(aim_is_end)
move_end = 1.0;
if(moveratio > move_end)
moveratio = move_end;
vect_show = vect_old + vect_move * moveratio;
}
bool is_moving()
{
return ((anim_time_counter / anim_time) < 1.4);
}
};
/*
TestCAO
*/
class TestCAO : public ClientActiveObject
{
public:
TestCAO(IGameDef *gamedef, ClientEnvironment *env);
virtual ~TestCAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_TEST;
}
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr);
void removeFromScene();
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
private:
scene::IMeshSceneNode *m_node;
v3f m_position;
};
/*
ItemCAO
*/
class ItemCAO : public ClientActiveObject
{
public:
ItemCAO(IGameDef *gamedef, ClientEnvironment *env);
virtual ~ItemCAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_ITEM;
}
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr);
void removeFromScene();
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
void initialize(const std::string &data);
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return m_position;}
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
std::string m_inventorystring;
};
/*
RatCAO
*/
class RatCAO : public ClientActiveObject
{
public:
RatCAO(IGameDef *gamedef, ClientEnvironment *env);
virtual ~RatCAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_RAT;
}
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr);
void removeFromScene();
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
void initialize(const std::string &data);
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return pos_translator.vect_show;}
//{return m_position;}
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
};
/*
Oerkki1CAO
*/
class Oerkki1CAO : public ClientActiveObject
{
public:
Oerkki1CAO(IGameDef *gamedef, ClientEnvironment *env);
virtual ~Oerkki1CAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_OERKKI1;
}
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr);
void removeFromScene();
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
void initialize(const std::string &data);
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return pos_translator.vect_show;}
//{return m_position;}
// If returns true, punch will not be sent to the server
bool directReportPunch(const std::string &toolname, v3f dir);
private:
IntervalLimiter m_attack_interval;
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
float m_damage_visual_timer;
bool m_damage_texture_enabled;
};
/*
FireflyCAO
*/
class FireflyCAO : public ClientActiveObject
{
public:
FireflyCAO(IGameDef *gamedef, ClientEnvironment *env);
virtual ~FireflyCAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_FIREFLY;
}
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr);
void removeFromScene();
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
void initialize(const std::string &data);
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return m_position;}
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
};
/*
MobV2CAO
*/
class MobV2CAO : public ClientActiveObject
{
public:
MobV2CAO(IGameDef *gamedef, ClientEnvironment *env);
virtual ~MobV2CAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_MOBV2;
}
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr);
void removeFromScene();
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
void initialize(const std::string &data);
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return pos_translator.vect_show;}
//{return m_position;}
bool doShowSelectionBox(){return false;}
// If returns true, punch will not be sent to the server
bool directReportPunch(const std::string &toolname, v3f dir);
private:
void setLooks(const std::string &looks);
IntervalLimiter m_attack_interval;
core::aabbox3d<f32> m_selection_box;
scene::MyBillboardSceneNode *m_node;
v3f m_position;
std::string m_texture_name;
float m_yaw;
SmoothTranslator pos_translator;
bool m_walking;
float m_walking_unset_timer;
float m_walk_timer;
int m_walk_frame;
float m_damage_visual_timer;
u8 m_last_light;
bool m_shooting;
float m_shooting_unset_timer;
v2f m_sprite_size;
float m_sprite_y;
bool m_bright_shooting;
std::string m_sprite_type;
int m_simple_anim_frames;
float m_simple_anim_frametime;
bool m_lock_full_brightness;
int m_player_hit_damage;
float m_player_hit_distance;
float m_player_hit_interval;
float m_player_hit_timer;
Settings *m_properties;
};
/*
TestCAO
*/
// Prototype
TestCAO proto_TestCAO(NULL);
TestCAO proto_TestCAO(NULL, NULL);
TestCAO::TestCAO(IGameDef *gamedef):
ClientActiveObject(0, gamedef),
TestCAO::TestCAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_node(NULL),
m_position(v3f(0,10*BS,0))
{
@@ -46,12 +420,13 @@ TestCAO::~TestCAO()
{
}
ClientActiveObject* TestCAO::create(IGameDef *gamedef)
ClientActiveObject* TestCAO::create(IGameDef *gamedef, ClientEnvironment *env)
{
return new TestCAO(gamedef);
return new TestCAO(gamedef, env);
}
void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
@@ -147,10 +522,10 @@ void TestCAO::processMessage(const std::string &data)
#include "inventory.h"
// Prototype
ItemCAO proto_ItemCAO(NULL);
ItemCAO proto_ItemCAO(NULL, NULL);
ItemCAO::ItemCAO(IGameDef *gamedef):
ClientActiveObject(0, gamedef),
ItemCAO::ItemCAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.),
m_node(NULL),
m_position(v3f(0,10*BS,0))
@@ -162,12 +537,13 @@ ItemCAO::~ItemCAO()
{
}
ClientActiveObject* ItemCAO::create(IGameDef *gamedef)
ClientActiveObject* ItemCAO::create(IGameDef *gamedef, ClientEnvironment *env)
{
return new ItemCAO(gamedef);
return new ItemCAO(gamedef, env);
}
void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
@@ -255,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()
@@ -288,7 +664,7 @@ void ItemCAO::step(float dtime, ClientEnvironment *env)
void ItemCAO::processMessage(const std::string &data)
{
infostream<<"ItemCAO: Got message"<<std::endl;
//infostream<<"ItemCAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
@@ -327,10 +703,10 @@ void ItemCAO::initialize(const std::string &data)
#include "inventory.h"
// Prototype
RatCAO proto_RatCAO(NULL);
RatCAO proto_RatCAO(NULL, NULL);
RatCAO::RatCAO(IGameDef *gamedef):
ClientActiveObject(0, gamedef),
RatCAO::RatCAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
m_node(NULL),
m_position(v3f(0,10*BS,0)),
@@ -343,12 +719,13 @@ RatCAO::~RatCAO()
{
}
ClientActiveObject* RatCAO::create(IGameDef *gamedef)
ClientActiveObject* RatCAO::create(IGameDef *gamedef, ClientEnvironment *env)
{
return new RatCAO(gamedef);
return new RatCAO(gamedef, env);
}
void RatCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
void RatCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
@@ -402,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()
@@ -472,10 +849,10 @@ void RatCAO::initialize(const std::string &data)
#include "inventory.h"
// Prototype
Oerkki1CAO proto_Oerkki1CAO(NULL);
Oerkki1CAO proto_Oerkki1CAO(NULL, NULL);
Oerkki1CAO::Oerkki1CAO(IGameDef *gamedef):
ClientActiveObject(0, gamedef),
Oerkki1CAO::Oerkki1CAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.,BS/3.),
m_node(NULL),
m_position(v3f(0,10*BS,0)),
@@ -490,12 +867,13 @@ Oerkki1CAO::~Oerkki1CAO()
{
}
ClientActiveObject* Oerkki1CAO::create(IGameDef *gamedef)
ClientActiveObject* Oerkki1CAO::create(IGameDef *gamedef, ClientEnvironment *env)
{
return new Oerkki1CAO(gamedef);
return new Oerkki1CAO(gamedef, env);
}
void Oerkki1CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
void Oerkki1CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
@@ -557,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()
@@ -712,10 +1090,10 @@ bool Oerkki1CAO::directReportPunch(const std::string &toolname, v3f dir)
*/
// Prototype
FireflyCAO proto_FireflyCAO(NULL);
FireflyCAO proto_FireflyCAO(NULL, NULL);
FireflyCAO::FireflyCAO(IGameDef *gamedef):
ClientActiveObject(0, gamedef),
FireflyCAO::FireflyCAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
m_node(NULL),
m_position(v3f(0,10*BS,0)),
@@ -728,12 +1106,13 @@ FireflyCAO::~FireflyCAO()
{
}
ClientActiveObject* FireflyCAO::create(IGameDef *gamedef)
ClientActiveObject* FireflyCAO::create(IGameDef *gamedef, ClientEnvironment *env)
{
return new FireflyCAO(gamedef);
return new FireflyCAO(gamedef, env);
}
void FireflyCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
void FireflyCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
@@ -787,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()
@@ -855,10 +1234,10 @@ void FireflyCAO::initialize(const std::string &data)
*/
// Prototype
MobV2CAO proto_MobV2CAO(NULL);
MobV2CAO proto_MobV2CAO(NULL, NULL);
MobV2CAO::MobV2CAO(IGameDef *gamedef):
ClientActiveObject(0, gamedef),
MobV2CAO::MobV2CAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-0.4*BS,-0.4*BS,-0.4*BS, 0.4*BS,0.8*BS,0.4*BS),
m_node(NULL),
m_position(v3f(0,10*BS,0)),
@@ -887,12 +1266,13 @@ MobV2CAO::~MobV2CAO()
delete m_properties;
}
ClientActiveObject* MobV2CAO::create(IGameDef *gamedef)
ClientActiveObject* MobV2CAO::create(IGameDef *gamedef, ClientEnvironment *env)
{
return new MobV2CAO(gamedef);
return new MobV2CAO(gamedef, env);
}
void MobV2CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
void MobV2CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
@@ -1269,7 +1649,7 @@ void MobV2CAO::setLooks(const std::string &looks)
#include "luaentity_common.h"
class CLuaEntityCAO : public LuaEntityCAO
class LuaEntityCAO : public ClientActiveObject
{
private:
core::aabbox3d<f32> m_selection_box;
@@ -1291,8 +1671,8 @@ class CLuaEntityCAO : public LuaEntityCAO
float m_anim_timer;
public:
CLuaEntityCAO(IGameDef *gamedef):
LuaEntityCAO(gamedef),
LuaEntityCAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
m_meshnode(NULL),
m_spritenode(NULL),
@@ -1309,12 +1689,13 @@ class CLuaEntityCAO : public LuaEntityCAO
m_anim_framelength(0.2),
m_anim_timer(0)
{
ClientActiveObject::registerType(getType(), create);
if(gamedef == NULL)
ClientActiveObject::registerType(getType(), create);
}
void initialize(const std::string &data)
{
infostream<<"CLuaEntityCAO: Got init data"<<std::endl;
infostream<<"LuaEntityCAO: Got init data"<<std::endl;
std::istringstream is(data, std::ios::binary);
// version
@@ -1346,14 +1727,14 @@ class CLuaEntityCAO : public LuaEntityCAO
updateNodePos();
}
~CLuaEntityCAO()
~LuaEntityCAO()
{
delete m_prop;
}
static ClientActiveObject* create(IGameDef *gamedef)
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
{
return new CLuaEntityCAO(gamedef);
return new LuaEntityCAO(gamedef, env);
}
u8 getType() const
@@ -1369,7 +1750,8 @@ class CLuaEntityCAO : public LuaEntityCAO
return pos_translator.vect_show;
}
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_meshnode != NULL || m_spritenode != NULL)
return;
@@ -1377,7 +1759,7 @@ class CLuaEntityCAO : public LuaEntityCAO
//video::IVideoDriver* driver = smgr->getVideoDriver();
if(m_prop->visual == "sprite"){
infostream<<"CLuaEntityCAO::addToScene(): single_sprite"<<std::endl;
infostream<<"LuaEntityCAO::addToScene(): single_sprite"<<std::endl;
m_spritenode = new scene::MyBillboardSceneNode(
smgr->getRootSceneNode(), smgr, -1, v3f(0,0,0), v2f(1,1));
m_spritenode->setMaterialTexture(0,
@@ -1398,7 +1780,7 @@ class CLuaEntityCAO : public LuaEntityCAO
m_spritenode->setTCoords(3, v2f(txs*0, tys*1));
}
} else if(m_prop->visual == "cube"){
infostream<<"CLuaEntityCAO::addToScene(): cube"<<std::endl;
infostream<<"LuaEntityCAO::addToScene(): cube"<<std::endl;
video::SColor c(255,255,255,255);
video::S3DVertex vertices[24] =
{
@@ -1461,7 +1843,7 @@ class CLuaEntityCAO : public LuaEntityCAO
// Will be shown when we know the brightness
m_meshnode->setVisible(false);
} else {
infostream<<"CLuaEntityCAO::addToScene(): \""<<m_prop->visual
infostream<<"LuaEntityCAO::addToScene(): \""<<m_prop->visual
<<"\" not supported"<<std::endl;
}
updateTextures("");
@@ -1485,7 +1867,7 @@ class CLuaEntityCAO : public LuaEntityCAO
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){
@@ -1640,7 +2022,7 @@ class CLuaEntityCAO : public LuaEntityCAO
void processMessage(const std::string &data)
{
infostream<<"CLuaEntityCAO: Got message"<<std::endl;
//infostream<<"LuaEntityCAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
@@ -1692,6 +2074,272 @@ class CLuaEntityCAO : public LuaEntityCAO
};
// Prototype
CLuaEntityCAO proto_CLuaEntityCAO(NULL);
LuaEntityCAO proto_LuaEntityCAO(NULL, NULL);
/*
PlayerCAO
*/
class PlayerCAO : public ClientActiveObject
{
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
scene::ITextSceneNode* m_text;
std::string m_name;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
bool m_is_local_player;
LocalPlayer *m_local_player;
float m_damage_visual_timer;
public:
PlayerCAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.0,BS/3.),
m_node(NULL),
m_text(NULL),
m_position(v3f(0,10*BS,0)),
m_yaw(0),
m_is_local_player(false),
m_local_player(NULL),
m_damage_visual_timer(0)
{
if(gamedef == NULL)
ClientActiveObject::registerType(getType(), create);
}
void initialize(const std::string &data)
{
infostream<<"PlayerCAO: Got init data"<<std::endl;
std::istringstream is(data, std::ios::binary);
// version
u8 version = readU8(is);
// check version
if(version != 0)
return;
// name
m_name = deSerializeString(is);
// pos
m_position = readV3F1000(is);
// yaw
m_yaw = readF1000(is);
pos_translator.init(m_position);
Player *player = m_env->getPlayer(m_name.c_str());
if(player && player->isLocal()){
m_is_local_player = true;
m_local_player = (LocalPlayer*)player;
}
}
~PlayerCAO()
{
if(m_node)
m_node->remove();
}
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
{
return new PlayerCAO(gamedef, env);
}
u8 getType() const
{
return ACTIVEOBJECT_TYPE_PLAYER;
}
core::aabbox3d<f32>* getSelectionBox()
{
if(m_is_local_player)
return NULL;
return &m_selection_box;
}
v3f getPosition()
{
return pos_translator.vect_show;
}
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
if(m_is_local_player)
return;
//video::IVideoDriver* driver = smgr->getVideoDriver();
gui::IGUIEnvironment* gui = irr->getGUIEnvironment();
scene::SMesh *mesh = new scene::SMesh();
{ // Front
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
{ // Back
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
// Set it to use the materials of the meshbuffers directly.
// This is needed for changing the texture in the future
m_node->setReadOnlyMaterials(true);
updateNodePos();
// Add a text node for showing the name
std::wstring wname = narrow_to_wide(m_name);
m_text = smgr->addTextSceneNode(gui->getBuiltInFont(),
wname.c_str(), video::SColor(255,255,255,255), m_node);
m_text->setPosition(v3f(0, (f32)BS*2.1, 0));
updateTextures("");
updateNodePos();
}
void removeFromScene()
{
if(m_node == NULL)
return;
m_node->remove();
m_node = NULL;
}
void updateLight(u8 light_at_pos)
{
if(m_node == NULL)
return;
m_node->setVisible(true);
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
setMeshColor(m_node->getMesh(), color);
}
v3s16 getLightPosition()
{
return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
}
void updateNodePos()
{
if(m_node == NULL)
return;
m_node->setPosition(pos_translator.vect_show);
v3f rot = m_node->getRotation();
rot.Y = -m_yaw;
m_node->setRotation(rot);
}
void step(float dtime, ClientEnvironment *env)
{
pos_translator.translate(dtime);
updateNodePos();
if(m_damage_visual_timer > 0){
m_damage_visual_timer -= dtime;
if(m_damage_visual_timer <= 0){
updateTextures("");
}
}
}
void processMessage(const std::string &data)
{
//infostream<<"PlayerCAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
if(cmd == 0) // update position
{
// pos
m_position = readV3F1000(is);
// yaw
m_yaw = readF1000(is);
pos_translator.update(m_position, false);
updateNodePos();
}
else if(cmd == 1) // punched
{
// damage
s16 damage = readS16(is);
if(m_is_local_player)
m_env->damageLocalPlayer(damage, false);
m_damage_visual_timer = 0.5;
updateTextures("^[brighten");
}
}
void updateTextures(const std::string &mod)
{
if(!m_node)
return;
ITextureSource *tsrc = m_gamedef->tsrc();
scene::IMesh *mesh = m_node->getMesh();
if(mesh){
{
std::string tname = "player.png";
tname += mod;
scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
buf->getMaterial().setTexture(0,
tsrc->getTextureRaw(tname));
}
{
std::string tname = "player_back.png";
tname += mod;
scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
buf->getMaterial().setTexture(0,
tsrc->getTextureRaw(tname));
}
}
}
};
// Prototype
PlayerCAO proto_PlayerCAO(NULL, NULL);

View File

@@ -20,398 +20,5 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef CONTENT_CAO_HEADER
#define CONTENT_CAO_HEADER
#include "clientobject.h"
#include "content_object.h"
#include "utility.h" // For IntervalLimiter
class Settings;
#include "MyBillboardSceneNode.h"
/*
SmoothTranslator
*/
struct SmoothTranslator
{
v3f vect_old;
v3f vect_show;
v3f vect_aim;
f32 anim_counter;
f32 anim_time;
f32 anim_time_counter;
bool aim_is_end;
SmoothTranslator():
vect_old(0,0,0),
vect_show(0,0,0),
vect_aim(0,0,0),
anim_counter(0),
anim_time(0),
anim_time_counter(0),
aim_is_end(true)
{}
void init(v3f vect)
{
vect_old = vect;
vect_show = vect;
vect_aim = vect;
anim_counter = 0;
anim_time = 0;
anim_time_counter = 0;
aim_is_end = true;
}
void sharpen()
{
init(vect_show);
}
void update(v3f vect_new, bool is_end_position=false, float update_interval=-1)
{
aim_is_end = is_end_position;
vect_old = vect_show;
vect_aim = vect_new;
if(update_interval > 0){
anim_time = update_interval;
} else {
if(anim_time < 0.001 || anim_time > 1.0)
anim_time = anim_time_counter;
else
anim_time = anim_time * 0.9 + anim_time_counter * 0.1;
}
anim_time_counter = 0;
anim_counter = 0;
}
void translate(f32 dtime)
{
anim_time_counter = anim_time_counter + dtime;
anim_counter = anim_counter + dtime;
v3f vect_move = vect_aim - vect_old;
f32 moveratio = 1.0;
if(anim_time > 0.001)
moveratio = anim_time_counter / anim_time;
// Move a bit less than should, to avoid oscillation
moveratio = moveratio * 0.8;
float move_end = 1.5;
if(aim_is_end)
move_end = 1.0;
if(moveratio > move_end)
moveratio = move_end;
vect_show = vect_old + vect_move * moveratio;
}
bool is_moving()
{
return ((anim_time_counter / anim_time) < 1.4);
}
};
/*
TestCAO
*/
class TestCAO : public ClientActiveObject
{
public:
TestCAO(IGameDef *gamedef);
virtual ~TestCAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_TEST;
}
static ClientActiveObject* create(IGameDef *gamedef);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc);
void removeFromScene();
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
private:
scene::IMeshSceneNode *m_node;
v3f m_position;
};
/*
ItemCAO
*/
class ItemCAO : public ClientActiveObject
{
public:
ItemCAO(IGameDef *gamedef);
virtual ~ItemCAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_ITEM;
}
static ClientActiveObject* create(IGameDef *gamedef);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc);
void removeFromScene();
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
void initialize(const std::string &data);
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return m_position;}
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
std::string m_inventorystring;
};
/*
RatCAO
*/
class RatCAO : public ClientActiveObject
{
public:
RatCAO(IGameDef *gamedef);
virtual ~RatCAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_RAT;
}
static ClientActiveObject* create(IGameDef *gamedef);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc);
void removeFromScene();
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
void initialize(const std::string &data);
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return pos_translator.vect_show;}
//{return m_position;}
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
};
/*
Oerkki1CAO
*/
class Oerkki1CAO : public ClientActiveObject
{
public:
Oerkki1CAO(IGameDef *gamedef);
virtual ~Oerkki1CAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_OERKKI1;
}
static ClientActiveObject* create(IGameDef *gamedef);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc);
void removeFromScene();
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
void initialize(const std::string &data);
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return pos_translator.vect_show;}
//{return m_position;}
// If returns true, punch will not be sent to the server
bool directReportPunch(const std::string &toolname, v3f dir);
private:
IntervalLimiter m_attack_interval;
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
float m_damage_visual_timer;
bool m_damage_texture_enabled;
};
/*
FireflyCAO
*/
class FireflyCAO : public ClientActiveObject
{
public:
FireflyCAO(IGameDef *gamedef);
virtual ~FireflyCAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_FIREFLY;
}
static ClientActiveObject* create(IGameDef *gamedef);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc);
void removeFromScene();
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
void initialize(const std::string &data);
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return m_position;}
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
};
/*
MobV2CAO
*/
class MobV2CAO : public ClientActiveObject
{
public:
MobV2CAO(IGameDef *gamedef);
virtual ~MobV2CAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_MOBV2;
}
static ClientActiveObject* create(IGameDef *gamedef);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc);
void removeFromScene();
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
void initialize(const std::string &data);
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return pos_translator.vect_show;}
//{return m_position;}
bool doShowSelectionBox(){return false;}
// If returns true, punch will not be sent to the server
bool directReportPunch(const std::string &toolname, v3f dir);
private:
void setLooks(const std::string &looks);
IntervalLimiter m_attack_interval;
core::aabbox3d<f32> m_selection_box;
scene::MyBillboardSceneNode *m_node;
v3f m_position;
std::string m_texture_name;
float m_yaw;
SmoothTranslator pos_translator;
bool m_walking;
float m_walking_unset_timer;
float m_walk_timer;
int m_walk_frame;
float m_damage_visual_timer;
u8 m_last_light;
bool m_shooting;
float m_shooting_unset_timer;
v2f m_sprite_size;
float m_sprite_y;
bool m_bright_shooting;
std::string m_sprite_type;
int m_simple_anim_frames;
float m_simple_anim_frametime;
bool m_lock_full_brightness;
int m_player_hit_damage;
float m_player_hit_distance;
float m_player_hit_interval;
float m_player_hit_timer;
Settings *m_properties;
};
/*
LuaEntityCAO
*/
class LuaEntityCAO : public ClientActiveObject
{
public:
LuaEntityCAO(IGameDef *gamedef):
ClientActiveObject(0, gamedef)
{}
virtual ~LuaEntityCAO(){}
virtual u8 getType() const=0;
virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)=0;
virtual void removeFromScene()=0;
virtual void updateLight(u8 light_at_pos)=0;
virtual v3s16 getLightPosition()=0;
virtual void updateNodePos()=0;
virtual void step(float dtime, ClientEnvironment *env)=0;
virtual void processMessage(const std::string &data)=0;
virtual void initialize(const std::string &data)=0;
virtual core::aabbox3d<f32>* getSelectionBox()=0;
virtual v3f getPosition()=0;
private:
};
#endif

View File

@@ -1,127 +0,0 @@
/*
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 "content_craft.h"
#include "inventory.h"
#include "content_mapnode.h"
#include "player.h"
#include "mapnode.h" // For content_t
#include "gamedef.h"
void craft_set_creative_inventory(Player *player, IGameDef *gamedef)
{
INodeDefManager *ndef = gamedef->ndef();
player->resetInventory();
// Give some good tools
{
InventoryItem *item = new ToolItem(gamedef, "MesePick", 0);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
{
InventoryItem *item = new ToolItem(gamedef, "SteelPick", 0);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
{
InventoryItem *item = new ToolItem(gamedef, "SteelAxe", 0);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
{
InventoryItem *item = new ToolItem(gamedef, "SteelShovel", 0);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
/*
Give materials
*/
// CONTENT_IGNORE-terminated list
content_t material_items[] = {
LEGN(ndef, "CONTENT_TORCH"),
LEGN(ndef, "CONTENT_COBBLE"),
LEGN(ndef, "CONTENT_MUD"),
LEGN(ndef, "CONTENT_STONE"),
LEGN(ndef, "CONTENT_SAND"),
LEGN(ndef, "CONTENT_SANDSTONE"),
LEGN(ndef, "CONTENT_CLAY"),
LEGN(ndef, "CONTENT_BRICK"),
LEGN(ndef, "CONTENT_TREE"),
LEGN(ndef, "CONTENT_LEAVES"),
LEGN(ndef, "CONTENT_CACTUS"),
LEGN(ndef, "CONTENT_PAPYRUS"),
LEGN(ndef, "CONTENT_BOOKSHELF"),
LEGN(ndef, "CONTENT_GLASS"),
LEGN(ndef, "CONTENT_FENCE"),
LEGN(ndef, "CONTENT_RAIL"),
LEGN(ndef, "CONTENT_MESE"),
LEGN(ndef, "CONTENT_WATERSOURCE"),
LEGN(ndef, "CONTENT_CLOUD"),
LEGN(ndef, "CONTENT_CHEST"),
LEGN(ndef, "CONTENT_FURNACE"),
LEGN(ndef, "CONTENT_SIGN_WALL"),
LEGN(ndef, "CONTENT_LAVASOURCE"),
CONTENT_IGNORE
};
content_t *mip = material_items;
for(u16 i=0; i<PLAYER_INVENTORY_SIZE; i++)
{
if(*mip == CONTENT_IGNORE)
break;
InventoryItem *item = new MaterialItem(gamedef, *mip, 1);
player->inventory.addItem("main", item);
mip++;
}
#if 0
assert(USEFUL_LEGN(ndef, "CONTENT_COUNT") <= PLAYER_INVENTORY_SIZE);
// add torch first
InventoryItem *item = new MaterialItem(gamedef, LEGN(ndef, "CONTENT_TORCH"), 1);
player->inventory.addItem("main", item);
// Then others
for(u16 i=0; i<USEFUL_LEGN(ndef, "CONTENT_COUNT"); i++)
{
// Skip some materials
if(i == LEGN(ndef, "CONTENT_WATER") || i == LEGN(ndef, "CONTENT_TORCH")
|| i == LEGN(ndef, "CONTENT_COALSTONE"))
continue;
InventoryItem *item = new MaterialItem(gamedef, i, 1);
player->inventory.addItem("main", item);
}
#endif
/*// Sign
{
InventoryItem *item = new MapBlockObjectItem(gamedef, "Sign Example text");
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}*/
}

View File

@@ -1,30 +0,0 @@
/*
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 CONTENT_CRAFT_HEADER
#define CONTENT_CRAFT_HEADER
class InventoryItem;
class Player;
class IGameDef;
void craft_set_creative_inventory(Player *player, IGameDef *gamedef);
#endif

View File

@@ -32,6 +32,9 @@ class Inventory;
#define NODEMETA_FURNACE 16
#define NODEMETA_LOCKABLE_CHEST 17
core::map<u16, NodeMetadata::Factory> NodeMetadata::m_types;
core::map<std::string, NodeMetadata::Factory2> NodeMetadata::m_names;
class SignNodeMetadata : public NodeMetadata
{
public:

View File

@@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define ACTIVEOBJECT_TYPE_LUAENTITY 7
// Special type, not stored in active object lists
// Special type, not stored as a static object
#define ACTIVEOBJECT_TYPE_PLAYER 100
#endif

View File

@@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "main.h" // For g_profiler
#include "profiler.h"
#include "serialization.h" // For compressZlib
#include "materials.h" // For MaterialProperties
#include "tooldef.h" // ToolDiggingProperties
core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
@@ -241,7 +243,7 @@ InventoryItem * ItemSAO::createInventoryItem()
}
}
void ItemSAO::punch(ServerActiveObject *puncher)
void ItemSAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
InventoryItem *item = createInventoryItem();
bool fits = puncher->addToInventory(item);
@@ -432,7 +434,7 @@ std::string RatSAO::getStaticData()
return os.str();
}
void RatSAO::punch(ServerActiveObject *puncher)
void RatSAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
std::istringstream is("CraftItem rat 1", std::ios_base::binary);
IGameDef *gamedef = m_env->getGameDef();
@@ -687,36 +689,28 @@ std::string Oerkki1SAO::getStaticData()
return os.str();
}
void Oerkki1SAO::punch(ServerActiveObject *puncher)
void Oerkki1SAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
if(!puncher)
return;
v3f dir = (getBasePosition() - puncher->getBasePosition()).normalize();
std::string toolname = "";
InventoryItem *item = puncher->getWieldedItem();
if(item && (std::string)item->getName() == "ToolItem"){
ToolItem *titem = (ToolItem*)item;
toolname = titem->getToolName();
}
m_speed_f += dir*12*BS;
u16 amount = 5;
/* See tool names in inventory.h */
if(toolname == "WSword")
amount = 10;
if(toolname == "STSword")
amount = 12;
if(toolname == "SteelSword")
amount = 16;
if(toolname == "STAxe")
amount = 7;
if(toolname == "SteelAxe")
amount = 9;
if(toolname == "SteelPick")
amount = 7;
doDamage(amount);
puncher->damageWieldedItem(65536/100);
// "Material" properties of an oerkki
MaterialProperties mp;
mp.diggability = DIGGABLE_NORMAL;
mp.crackiness = -1.0;
mp.cuttability = 1.0;
ToolDiggingProperties tp;
puncher->getWieldDiggingProperties(&tp);
HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch);
doDamage(hitprop.hp);
puncher->damageWieldedItem(hitprop.wear);
}
void Oerkki1SAO::doDamage(u16 d)
@@ -919,14 +913,6 @@ std::string FireflySAO::getStaticData()
return os.str();
}
InventoryItem* FireflySAO::createPickedUpItem()
{
std::istringstream is("CraftItem firefly 1", std::ios_base::binary);
IGameDef *gamedef = m_env->getGameDef();
InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
return item;
}
/*
MobV2SAO
*/
@@ -1365,25 +1351,20 @@ void MobV2SAO::step(float dtime, bool send_recommended)
}
}
void MobV2SAO::punch(ServerActiveObject *puncher)
void MobV2SAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
if(!puncher)
return;
v3f dir = (getBasePosition() - puncher->getBasePosition()).normalize();
std::string toolname = "";
InventoryItem *item = puncher->getWieldedItem();
if(item && (std::string)item->getName() == "ToolItem"){
ToolItem *titem = (ToolItem*)item;
toolname = titem->getToolName();
}
// A quick hack; SAO description is player name for player
std::string playername = puncher->getDescription();
Map *map = &m_env->getMap();
actionstream<<playername<<" punches mob id="<<m_id
<<" with a \""<<toolname<<"\" at "
<<PP(m_base_position/BS)<<std::endl;
<<" at "<<PP(m_base_position/BS)<<std::endl;
m_disturb_timer = 0;
m_disturbing_player = playername;
@@ -1405,23 +1386,21 @@ void MobV2SAO::punch(ServerActiveObject *puncher)
}
sendPosition();
u16 amount = 2;
/* See tool names in inventory.h */
if(toolname == "WSword")
amount = 4;
if(toolname == "STSword")
amount = 6;
if(toolname == "SteelSword")
amount = 8;
if(toolname == "STAxe")
amount = 3;
if(toolname == "SteelAxe")
amount = 4;
if(toolname == "SteelPick")
amount = 3;
doDamage(amount);
puncher->damageWieldedItem(65536/100);
// "Material" properties of the MobV2
MaterialProperties mp;
mp.diggability = DIGGABLE_NORMAL;
mp.crackiness = -1.0;
mp.cuttability = 1.0;
ToolDiggingProperties tp;
puncher->getWieldDiggingProperties(&tp);
HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch);
doDamage(hitprop.hp);
puncher->damageWieldedItem(hitprop.wear);
}
bool MobV2SAO::isPeaceful()
@@ -1677,21 +1656,12 @@ std::string LuaEntitySAO::getStaticData()
return os.str();
}
InventoryItem* LuaEntitySAO::createPickedUpItem()
{
// TODO: Ask item from scriptapi
std::istringstream is("CraftItem testobject1 1", std::ios_base::binary);
IGameDef *gamedef = m_env->getGameDef();
InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
return item;
}
void LuaEntitySAO::punch(ServerActiveObject *puncher)
void LuaEntitySAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
if(!m_registered)
return;
lua_State *L = m_env->getLua();
scriptapi_luaentity_punch(L, m_id, puncher);
scriptapi_luaentity_punch(L, m_id, puncher, time_from_last_punch);
}
void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
@@ -1799,4 +1769,3 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
m_messages_out.push_back(aom);
}

View File

@@ -50,7 +50,7 @@ class ItemSAO : public ServerActiveObject
std::string getClientInitializationData();
std::string getStaticData();
InventoryItem* createInventoryItem();
void punch(ServerActiveObject *puncher);
void punch(ServerActiveObject *puncher, float time_from_last_punch);
float getMinimumSavedMovement(){ return 0.1*BS; }
private:
std::string m_inventorystring;
@@ -70,7 +70,7 @@ class RatSAO : public ServerActiveObject
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
void punch(ServerActiveObject *puncher);
void punch(ServerActiveObject *puncher, float time_from_last_punch);
private:
bool m_is_active;
IntervalLimiter m_inactive_interval;
@@ -95,8 +95,7 @@ class Oerkki1SAO : public ServerActiveObject
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
InventoryItem* createPickedUpItem(){return NULL;}
void punch(ServerActiveObject *puncher);
void punch(ServerActiveObject *puncher, float time_from_last_punch);
bool isPeaceful(){return false;}
private:
void doDamage(u16 d);
@@ -126,7 +125,6 @@ class FireflySAO : public ServerActiveObject
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
InventoryItem* createPickedUpItem();
private:
bool m_is_active;
IntervalLimiter m_inactive_interval;
@@ -155,8 +153,7 @@ class MobV2SAO : public ServerActiveObject
std::string getStaticData();
std::string getClientInitializationData();
void step(float dtime, bool send_recommended);
InventoryItem* createPickedUpItem(){return NULL;}
void punch(ServerActiveObject *puncher);
void punch(ServerActiveObject *puncher, float time_from_last_punch);
bool isPeaceful();
private:
void sendPosition();
@@ -209,8 +206,7 @@ class LuaEntitySAO : public ServerActiveObject
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
InventoryItem* createPickedUpItem();
void punch(ServerActiveObject *puncher);
void punch(ServerActiveObject *puncher, float time_from_last_punch);
void rightClick(ServerActiveObject *clicker);
void setPos(v3f pos);
void moveTo(v3f pos, bool continuous);

View File

@@ -93,10 +93,11 @@ void set_default_settings(Settings *settings)
settings->setDefault("give_initial_stuff", "false");
settings->setDefault("default_password", "");
settings->setDefault("default_privs", "build, shout");
settings->setDefault("unlimited_player_transfer_distance", "true");
settings->setDefault("enable_pvp", "true");
settings->setDefault("profiler_print_interval", "0");
settings->setDefault("enable_mapgen_debug_info", "false");
settings->setDefault("objectdata_interval", "0.2");
settings->setDefault("active_object_send_range_blocks", "3");
settings->setDefault("active_block_range", "2");
//settings->setDefault("max_simultaneous_block_sends_per_client", "1");
@@ -107,8 +108,8 @@ void set_default_settings(Settings *settings)
settings->setDefault("max_block_generate_distance", "5");
settings->setDefault("time_send_interval", "20");
settings->setDefault("time_speed", "96");
settings->setDefault("server_unload_unused_data_timeout", "19");
settings->setDefault("server_map_save_interval", "1.238");
settings->setDefault("server_unload_unused_data_timeout", "29");
settings->setDefault("server_map_save_interval", "5.3");
settings->setDefault("full_block_send_enable_min_time_from_building", "2.0");
settings->setDefault("enable_experimental", "false");
}

View File

@@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodemetadata.h"
#include "main.h" // For g_settings, g_profiler
#include "gamedef.h"
#include "serverremoteplayer.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@@ -491,7 +492,9 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir)
}
if(newplayer)
{
addPlayer(player);
}
}
}
@@ -741,10 +744,15 @@ void ServerEnvironment::clearAllObjects()
obj->m_removed = true;
continue;
}
// Tell the object about removal
obj->removingFromEnvironment();
// Deregister in scripting api
scriptapi_rm_object_reference(m_lua, obj);
// Delete active object
delete obj;
if(obj->environmentDeletes())
delete obj;
// Id to be removed from m_active_objects
objects_to_remove.push_back(id);
}
@@ -1175,7 +1183,8 @@ bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
succeeded = false;
}
delete obj;
if(obj->environmentDeletes())
delete obj;
return succeeded;
}
@@ -1209,10 +1218,12 @@ void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
// Discard if removed
if(object->m_removed)
continue;
// Discard if too far
f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
if(distance_f > radius_f)
continue;
if(object->unlimitedTransferDistance() == false){
// Discard if too far
f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
if(distance_f > radius_f)
continue;
}
// Discard if already on current_objects
core::map<u16, bool>::Node *n;
n = current_objects.find(id);
@@ -1247,24 +1258,33 @@ void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
{
u16 id = i.getNode()->getKey();
ServerActiveObject *object = getActiveObject(id);
if(object == NULL)
{
if(object == NULL){
infostream<<"ServerEnvironment::getRemovedActiveObjects():"
<<" object in current_objects is NULL"<<std::endl;
removed_objects.insert(id, false);
continue;
}
else if(object->m_removed == false)
if(object->m_removed)
{
f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
/*infostream<<"removed == false"
<<"distance_f = "<<distance_f
<<", radius_f = "<<radius_f<<std::endl;*/
if(distance_f < radius_f)
{
// Not removed
continue;
}
removed_objects.insert(id, false);
continue;
}
removed_objects.insert(id, false);
// If transfer distance is unlimited, don't remove
if(object->unlimitedTransferDistance())
continue;
f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
if(distance_f >= radius_f)
{
removed_objects.insert(id, false);
continue;
}
// Not removed
}
}
@@ -1290,7 +1310,8 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
{
errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
<<"no free ids available"<<std::endl;
delete object;
if(object->environmentDeletes())
delete object;
return 0;
}
object->setId(new_id);
@@ -1303,7 +1324,8 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
{
errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
<<"id is not free ("<<object->getId()<<")"<<std::endl;
delete object;
if(object->environmentDeletes())
delete object;
return 0;
}
/*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
@@ -1316,34 +1338,38 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
<<m_active_objects.size()<<" active objects."
<<std::endl;
// Add static object to active static list of the block
v3f objectpos = object->getBasePosition();
std::string staticdata = object->getStaticData();
StaticObject s_obj(object->getType(), objectpos, staticdata);
// Add to the block where the object is located in
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
if(block)
{
block->m_static_objects.m_active.insert(object->getId(), s_obj);
object->m_static_exists = true;
object->m_static_block = blockpos;
if(set_changed)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"addActiveObjectRaw");
}
else{
errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
<<"could not find block for storing id="<<object->getId()
<<" statically"<<std::endl;
}
// Register reference in scripting api (must be done before post-init)
scriptapi_add_object_reference(m_lua, object);
// Post-initialize object
object->addedToEnvironment();
// Add static data to block
if(object->isStaticAllowed())
{
// Add static object to active static list of the block
v3f objectpos = object->getBasePosition();
std::string staticdata = object->getStaticData();
StaticObject s_obj(object->getType(), objectpos, staticdata);
// Add to the block where the object is located in
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
if(block)
{
block->m_static_objects.m_active.insert(object->getId(), s_obj);
object->m_static_exists = true;
object->m_static_block = blockpos;
if(set_changed)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"addActiveObjectRaw");
}
else{
errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
<<"could not find block for storing id="<<object->getId()
<<" statically"<<std::endl;
}
}
return object->getId();
}
@@ -1395,11 +1421,14 @@ void ServerEnvironment::removeRemovedObjects()
if(obj->m_known_by_count > 0)
continue;
// Tell the object about removal
obj->removingFromEnvironment();
// Deregister in scripting api
scriptapi_rm_object_reference(m_lua, obj);
// Delete
delete obj;
if(obj->environmentDeletes())
delete obj;
// Id to be removed from m_active_objects
objects_to_remove.push_back(id);
}
@@ -1541,18 +1570,14 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
i.atEnd()==false; i++)
{
ServerActiveObject* obj = i.getNode()->getValue();
// This shouldn't happen but check it
if(obj == NULL)
{
errorstream<<"NULL object found in ServerEnvironment"
<<std::endl;
assert(0);
assert(obj);
// Do not deactivate if static data creation not allowed
if(!force_delete && !obj->isStaticAllowed())
continue;
}
// If pending deactivation, let removeRemovedObjects() do it
if(obj->m_pending_deactivation)
if(!force_delete && obj->m_pending_deactivation)
continue;
u16 id = i.getNode()->getKey();
@@ -1562,7 +1587,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
// If block is active, don't remove
if(m_active_blocks.contains(blockpos_o))
if(!force_delete && m_active_blocks.contains(blockpos_o))
continue;
verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
@@ -1576,97 +1601,102 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
Update the static data
*/
// Create new static object
std::string staticdata_new = obj->getStaticData();
StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
bool stays_in_same_block = false;
bool data_changed = true;
if(obj->m_static_exists){
if(obj->m_static_block == blockpos_o)
stays_in_same_block = true;
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
core::map<u16, StaticObject>::Node *n =
block->m_static_objects.m_active.find(id);
if(n){
StaticObject static_old = n->getValue();
float save_movem = obj->getMinimumSavedMovement();
if(static_old.data == staticdata_new &&
(static_old.pos - objectpos).getLength() < save_movem)
data_changed = false;
} else {
errorstream<<"ServerEnvironment::deactivateFarObjects(): "
<<"id="<<id<<" m_static_exists=true but "
<<"static data doesn't actually exist in "
<<PP(obj->m_static_block)<<std::endl;
}
}
bool shall_be_written = (!stays_in_same_block || data_changed);
// Delete old static object
if(obj->m_static_exists)
if(obj->isStaticAllowed())
{
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
// Create new static object
std::string staticdata_new = obj->getStaticData();
StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
bool stays_in_same_block = false;
bool data_changed = true;
if(obj->m_static_exists){
if(obj->m_static_block == blockpos_o)
stays_in_same_block = true;
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
core::map<u16, StaticObject>::Node *n =
block->m_static_objects.m_active.find(id);
if(n){
StaticObject static_old = n->getValue();
float save_movem = obj->getMinimumSavedMovement();
if(static_old.data == staticdata_new &&
(static_old.pos - objectpos).getLength() < save_movem)
data_changed = false;
} else {
errorstream<<"ServerEnvironment::deactivateFarObjects(): "
<<"id="<<id<<" m_static_exists=true but "
<<"static data doesn't actually exist in "
<<PP(obj->m_static_block)<<std::endl;
}
}
bool shall_be_written = (!stays_in_same_block || data_changed);
// Delete old static object
if(obj->m_static_exists)
{
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
if(block)
{
block->m_static_objects.remove(id);
obj->m_static_exists = false;
// Only mark block as modified if data changed considerably
if(shall_be_written)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"deactivateFarObjects: Static data "
"changed considerably");
}
}
// Add to the block where the object is located in
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
// Get or generate the block
MapBlock *block = m_map->emergeBlock(blockpos);
if(block)
{
block->m_static_objects.remove(id);
obj->m_static_exists = false;
// Only mark block as modified if data changed considerably
if(shall_be_written)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"deactivateFarObjects: Static data "
"changed considerably");
if(block->m_static_objects.m_stored.size() >= 49){
errorstream<<"ServerEnv: Trying to store id="<<obj->getId()
<<" statically but block "<<PP(blockpos)
<<" already contains "
<<block->m_static_objects.m_stored.size()
<<" (over 49) objects."
<<" Forcing delete."<<std::endl;
force_delete = true;
} else {
u16 new_id = pending_delete ? id : 0;
block->m_static_objects.insert(new_id, s_obj);
// Only mark block as modified if data changed considerably
if(shall_be_written)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"deactivateFarObjects: Static data "
"changed considerably");
obj->m_static_exists = true;
obj->m_static_block = block->getPos();
}
}
}
// Add to the block where the object is located in
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
// Get or generate the block
MapBlock *block = m_map->emergeBlock(blockpos);
if(block)
{
if(block->m_static_objects.m_stored.size() >= 49){
errorstream<<"ServerEnv: Trying to store id="<<obj->getId()
<<" statically but block "<<PP(blockpos)
<<" already contains "
<<block->m_static_objects.m_stored.size()
<<" (over 49) objects."
<<" Forcing delete."<<std::endl;
force_delete = true;
} else {
u16 new_id = pending_delete ? id : 0;
block->m_static_objects.insert(new_id, s_obj);
// Only mark block as modified if data changed considerably
if(shall_be_written)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"deactivateFarObjects: Static data "
"changed considerably");
obj->m_static_exists = true;
obj->m_static_block = block->getPos();
else{
if(!force_delete){
errorstream<<"ServerEnv: Could not find or generate "
<<"a block for storing id="<<obj->getId()
<<" statically"<<std::endl;
continue;
}
}
}
else{
errorstream<<"ServerEnv: Could not find or generate "
<<"a block for storing id="<<obj->getId()
<<" statically"<<std::endl;
continue;
}
/*
If known by some client, set pending deactivation.
Otherwise delete it immediately.
*/
if(pending_delete)
if(pending_delete && !force_delete)
{
verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
<<"object id="<<id<<" is known by clients"
@@ -1680,11 +1710,14 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
<<"object id="<<id<<" is not known by clients"
<<"; deleting"<<std::endl;
// Tell the object about removal
obj->removingFromEnvironment();
// Deregister in scripting api
scriptapi_rm_object_reference(m_lua, obj);
// Delete active object
delete obj;
if(obj->environmentDeletes())
delete obj;
// Id to be removed from m_active_objects
objects_to_remove.push_back(id);
}
@@ -1705,14 +1738,14 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
*/
ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
ITextureSource *texturesource, IGameDef *gamedef):
ITextureSource *texturesource, IGameDef *gamedef,
IrrlichtDevice *irr):
m_map(map),
m_smgr(smgr),
m_texturesource(texturesource),
m_gamedef(gamedef)
m_gamedef(gamedef),
m_irr(irr)
{
assert(m_map);
assert(m_smgr);
}
ClientEnvironment::~ClientEnvironment()
@@ -1887,6 +1920,7 @@ void ClientEnvironment::step(float dtime)
ClientEnvEvent event;
event.type = CEE_PLAYER_DAMAGE;
event.player_damage.amount = damage;
event.player_damage.send_to_server = true;
m_client_event_queue.push_back(event);
}
}
@@ -1920,6 +1954,7 @@ void ClientEnvironment::step(float dtime)
ClientEnvEvent event;
event.type = CEE_PLAYER_DAMAGE;
event.player_damage.amount = damage_per_second;
event.player_damage.send_to_server = true;
m_client_event_queue.push_back(event);
}
}
@@ -2088,7 +2123,7 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
infostream<<"ClientEnvironment::addActiveObject(): "
<<"added (id="<<object->getId()<<")"<<std::endl;
m_active_objects.insert(object->getId(), object);
object->addToScene(m_smgr, m_texturesource);
object->addToScene(m_smgr, m_texturesource, m_irr);
{ // Update lighting immediately
u8 light = 0;
try{
@@ -2106,7 +2141,8 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
void ClientEnvironment::addActiveObject(u16 id, u8 type,
const std::string &init_data)
{
ClientActiveObject* obj = ClientActiveObject::create(type, m_gamedef);
ClientActiveObject* obj =
ClientActiveObject::create(type, m_gamedef, this);
if(obj == NULL)
{
infostream<<"ClientEnvironment::addActiveObject(): "
@@ -2156,19 +2192,22 @@ void ClientEnvironment::processActiveObjectMessage(u16 id,
Callbacks for activeobjects
*/
void ClientEnvironment::damageLocalPlayer(u8 damage)
void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
{
LocalPlayer *lplayer = getLocalPlayer();
assert(lplayer);
if(lplayer->hp > damage)
lplayer->hp -= damage;
else
lplayer->hp = 0;
if(handle_hp){
if(lplayer->hp > damage)
lplayer->hp -= damage;
else
lplayer->hp = 0;
}
ClientEnvEvent event;
event.type = CEE_PLAYER_DAMAGE;
event.player_damage.amount = damage;
event.player_damage.send_to_server = handle_hp;
m_client_event_queue.push_back(event);
}

View File

@@ -368,6 +368,7 @@ struct ClientEnvEvent
} none;
struct{
u8 amount;
bool send_to_server;
} player_damage;
};
};
@@ -376,7 +377,8 @@ class ClientEnvironment : public Environment
{
public:
ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
ITextureSource *texturesource, IGameDef *gamedef);
ITextureSource *texturesource, IGameDef *gamedef,
IrrlichtDevice *device);
~ClientEnvironment();
Map & getMap()
@@ -436,7 +438,7 @@ class ClientEnvironment : public Environment
Callbacks for activeobjects
*/
void damageLocalPlayer(u8 damage);
void damageLocalPlayer(u8 damage, bool handle_hp=true);
/*
Client likes to call these
@@ -454,6 +456,7 @@ class ClientEnvironment : public Environment
scene::ISceneManager *m_smgr;
ITextureSource *m_texturesource;
IGameDef *m_gamedef;
IrrlichtDevice *m_irr;
core::map<u16, ClientActiveObject*> m_active_objects;
Queue<ClientEnvEvent> m_client_event_queue;
IntervalLimiter m_active_object_light_update_interval;

View File

@@ -265,9 +265,17 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s, ITextureSource *tsrc)
rect.LowerRightCorner + v2s32(1,1)*border),
&AbsoluteClippingRect);
}
video::SColor bgcolor(255,128,128,128);
driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
if(rect.isPointInside(m_pointer) && m_selected_item)
{
video::SColor bgcolor(255,192,192,192);
driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
}
else
{
video::SColor bgcolor(255,128,128,128);
driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
}
if(item)
{
@@ -319,22 +327,31 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
if(event.EventType==EET_MOUSE_INPUT_EVENT)
{
char amount = -1;
if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
v2s32 p(event.MouseInput.X, event.MouseInput.Y);
ItemSpec s = getItemAtPos(p);
if(event.MouseInput.Event==EMIE_MOUSE_MOVED)
m_pointer = v2s32(event.MouseInput.X, event.MouseInput.Y);
else if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
amount = 0;
else if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
amount = 1;
else if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN)
amount = 10;
else if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP &&
m_selected_item &&
(m_selected_item->listname != s.listname
|| m_selected_item->i != s.i))
amount = 0;
if(amount >= 0)
{
v2s32 p(event.MouseInput.X, event.MouseInput.Y);
//infostream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
ItemSpec s = getItemAtPos(p);
//infostream<<"Mouse action at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
if(s.isValid())
{
infostream<<"Mouse down on "<<s.inventoryname
infostream<<"Mouse action on "<<s.inventoryname
<<"/"<<s.listname<<" "<<s.i<<std::endl;
if(m_selected_item)
{
@@ -369,7 +386,7 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
//ispec.actions->push_back(a);
m_invmgr->inventoryAction(a);
if(list_from->getItem(m_selected_item->i)->getCount()==1)
if(list_from->getItem(m_selected_item->i)->getCount()<=amount)
source_empties = true;
}
// Remove selection if target was left-clicked or source

View File

@@ -159,6 +159,7 @@ class GUIInventoryMenu : public GUIModalMenu
core::array<ListDrawSpec> m_draw_spec;
ItemSpec *m_selected_item;
v2s32 m_pointer;
};
#endif

View File

@@ -36,6 +36,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gamedef.h"
#include "scriptapi.h"
#include "strfnd.h"
#include "nameidmapping.h" // For loading legacy MaterialItems
#include "serverremoteplayer.h"
/*
InventoryItem
@@ -97,7 +99,7 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is, IGameDef *gamedef)
throw SerializationError("Too large material number");
return new MaterialItem(gamedef, material, count);
}
else if(name == "NodeItem" || name == "MaterialItem3")
else if(name == "node" || name == "NodeItem" || name == "MaterialItem3")
{
std::string all;
std::getline(is, all, '\n');
@@ -124,7 +126,7 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is, IGameDef *gamedef)
std::getline(is, inventorystring, '|');
throw SerializationError("MBOItem not supported anymore");
}
else if(name == "CraftItem")
else if(name == "craft" || name == "CraftItem")
{
std::string all;
std::getline(is, all, '\n');
@@ -146,7 +148,7 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is, IGameDef *gamedef)
count = 1;
return new CraftItem(gamedef, subname, count);
}
else if(name == "ToolItem")
else if(name == "tool" || name == "ToolItem")
{
std::string all;
std::getline(is, all, '\n');
@@ -212,7 +214,7 @@ bool InventoryItem::dropOrPlace(ServerEnvironment *env,
s16 dropcount = getDropCount();
if(count < 0 || count > dropcount)
count = dropcount;
if(count < 0 || count > getCount());
if(count < 0 || count > getCount())
count = getCount();
if(count > 0)
{
@@ -250,8 +252,10 @@ MaterialItem::MaterialItem(IGameDef *gamedef, std::string nodename, u16 count):
MaterialItem::MaterialItem(IGameDef *gamedef, content_t content, u16 count):
InventoryItem(gamedef, count)
{
INodeDefManager *ndef = m_gamedef->ndef();
std::string nodename = ndef->get(content).name;
NameIdMapping legacy_nimap;
content_mapnode_get_name_id_mapping(&legacy_nimap);
std::string nodename;
legacy_nimap.getName(content, nodename);
if(nodename == "")
nodename = "unknown_block";
m_nodename = nodename;

View File

@@ -31,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class ServerActiveObject;
class ServerEnvironment;
class PointedThing;
struct PointedThing;
class ITextureSource;
class IGameDef;
@@ -158,7 +158,7 @@ class MaterialItem : public InventoryItem
}
virtual void serialize(std::ostream &os) const
{
os<<"NodeItem";
os<<"node";
os<<" \"";
os<<m_nodename;
os<<"\" ";
@@ -249,7 +249,7 @@ class CraftItem : public InventoryItem
}
virtual void serialize(std::ostream &os) const
{
os<<getName();
os<<"craft";
os<<" \"";
os<<m_subname;
os<<"\" ";
@@ -345,7 +345,7 @@ class ToolItem : public InventoryItem
}
virtual void serialize(std::ostream &os) const
{
os<<getName();
os<<"tool";
os<<" \"";
os<<m_toolname;
os<<"\" ";

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

View File

@@ -49,34 +49,65 @@ void MaterialProperties::deSerialize(std::istream &is)
flammability = readF1000(is);
}
DiggingProperties getDiggingProperties(u16 content, ToolDiggingProperties *tp,
INodeDefManager *nodemgr)
DiggingProperties getDiggingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch)
{
assert(tp);
const MaterialProperties &mp = nodemgr->get(content).material;
if(mp.diggability == DIGGABLE_NOT)
if(mp->diggability == DIGGABLE_NOT)
return DiggingProperties(false, 0, 0);
if(mp.diggability == DIGGABLE_CONSTANT)
return DiggingProperties(true, mp.constant_time, 0);
if(mp->diggability == DIGGABLE_CONSTANT)
return DiggingProperties(true, mp->constant_time, 0);
float time = tp->basetime;
time += tp->dt_weight * mp.weight;
time += tp->dt_crackiness * mp.crackiness;
time += tp->dt_crumbliness * mp.crumbliness;
time += tp->dt_cuttability * mp.cuttability;
time += tp->dt_weight * mp->weight;
time += tp->dt_crackiness * mp->crackiness;
time += tp->dt_crumbliness * mp->crumbliness;
time += tp->dt_cuttability * mp->cuttability;
if(time < 0.2)
time = 0.2;
float durability = tp->basedurability;
durability += tp->dd_weight * mp.weight;
durability += tp->dd_crackiness * mp.crackiness;
durability += tp->dd_crumbliness * mp.crumbliness;
durability += tp->dd_cuttability * mp.cuttability;
durability += tp->dd_weight * mp->weight;
durability += tp->dd_crackiness * mp->crackiness;
durability += tp->dd_crumbliness * mp->crumbliness;
durability += tp->dd_cuttability * mp->cuttability;
if(durability < 1)
durability = 1;
if(time_from_last_punch < tp->full_punch_interval){
float f = time_from_last_punch / tp->full_punch_interval;
time /= f;
durability /= f;
}
float wear = 1.0 / durability;
u16 wear_i = 65535.*wear;
return DiggingProperties(true, time, wear_i);
}
DiggingProperties getDiggingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp)
{
return getDiggingProperties(mp, tp, 1000000);
}
DiggingProperties getDiggingProperties(u16 content,
const ToolDiggingProperties *tp, INodeDefManager *nodemgr)
{
const MaterialProperties &mp = nodemgr->get(content).material;
return getDiggingProperties(&mp, tp);
}
HittingProperties getHittingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch)
{
DiggingProperties digprop = getDiggingProperties(mp, tp,
time_from_last_punch);
// If digging time would be 1 second, 2 hearts go in 1 second.
s16 hp = 2.0 * 2.0 / digprop.time + 0.5;
// Wear is the same as for digging a single node
s16 wear = (float)digprop.wear + 0.5;
return HittingProperties(hp, wear);
}

View File

@@ -74,30 +74,44 @@ struct MaterialProperties
struct DiggingProperties
{
DiggingProperties():
diggable(false),
time(0.0),
wear(0)
{
}
DiggingProperties(bool a_diggable, float a_time, u16 a_wear):
diggable(a_diggable),
time(a_time),
wear(a_wear)
{
}
bool diggable;
// Digging time in seconds
float time;
// Caused wear
u16 wear;
DiggingProperties(bool a_diggable=false, float a_time=0, u16 a_wear=0):
diggable(a_diggable),
time(a_time),
wear(a_wear)
{}
};
class ToolDiggingProperties;
struct ToolDiggingProperties;
class INodeDefManager;
DiggingProperties getDiggingProperties(u16 content, ToolDiggingProperties *tp,
INodeDefManager *nodemgr);
DiggingProperties getDiggingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch);
DiggingProperties getDiggingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp);
DiggingProperties getDiggingProperties(u16 content,
const ToolDiggingProperties *tp, INodeDefManager *nodemgr);
struct HittingProperties
{
s16 hp;
s16 wear;
HittingProperties(s16 hp_=0, s16 wear_=0):
hp(hp_),
wear(wear_)
{}
};
HittingProperties getHittingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch);
#endif

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

@@ -216,7 +216,8 @@ void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
if(readU8(is) != 6)
throw SerializationError("unsupported tile count");
for(u32 i=0; i<6; i++)
tname_tiles[i] = deSerializeString(is);
setTexture(i, deSerializeString(is));
//tname_tiles[i] = deSerializeString(is);
tname_inventory = deSerializeString(is);
if(readU8(is) != CF_SPECIAL_COUNT)
throw SerializationError("unsupported CF_SPECIAL_COUNT");
@@ -280,7 +281,7 @@ void ContentFeatures::setSpecialMaterial(u16 i, const MaterialSpec &mspec)
void ContentFeatures::setInventoryTexture(std::string imgname)
{
tname_inventory = imgname + "^[forcesingle";
tname_inventory = imgname;
}
void ContentFeatures::setInventoryTextureCube(std::string top,
@@ -529,10 +530,10 @@ class CNodeDefManager: public IWritableNodeDefManager
f->visual_solidness = 1;
} else {
f->drawtype = NDT_NORMAL;
f->solidness = 1;
f->solidness = 2;
for(u32 i=0; i<6; i++){
f->tname_tiles[i] = f->tname_tiles[i]
+ std::string("^[noalpha");
f->setTexture(i, f->tname_tiles[i]
+ std::string("^[noalpha"));
}
}
break;

View File

@@ -30,9 +30,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
NodeMetadata
*/
core::map<u16, NodeMetadata::Factory> NodeMetadata::m_types;
core::map<std::string, NodeMetadata::Factory2> NodeMetadata::m_names;
NodeMetadata::NodeMetadata(IGameDef *gamedef):
m_gamedef(gamedef)
{

View File

@@ -175,275 +175,6 @@ void Player::deSerialize(std::istream &is)
inventory.deSerialize(is, m_gamedef);
}
/*
ServerRemotePlayer
*/
ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env):
Player(env->getGameDef()),
ServerActiveObject(env, v3f(0,0,0)),
m_last_good_position(0,0,0),
m_last_good_position_age(0),
m_additional_items(),
m_inventory_not_sent(false),
m_hp_not_sent(false)
{
}
ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 peer_id_,
const char *name_):
Player(env->getGameDef()),
ServerActiveObject(env, pos_),
m_inventory_not_sent(false),
m_hp_not_sent(false)
{
setPosition(pos_);
peer_id = peer_id_;
updateName(name_);
}
ServerRemotePlayer::~ServerRemotePlayer()
{
clearAddToInventoryLater();
}
/* ServerActiveObject interface */
InventoryItem* ServerRemotePlayer::getWieldedItem()
{
InventoryList *list = inventory.getList("main");
if (list)
return list->getItem(m_selected_item);
return NULL;
}
void ServerRemotePlayer::damageWieldedItem(u16 amount)
{
infostream<<"Damaging "<<getName()<<"'s wielded item for amount="
<<amount<<std::endl;
InventoryList *list = inventory.getList("main");
if(!list)
return;
InventoryItem *item = list->getItem(m_selected_item);
if(item && (std::string)item->getName() == "ToolItem"){
ToolItem *titem = (ToolItem*)item;
bool weared_out = titem->addWear(amount);
if(weared_out)
list->deleteItem(m_selected_item);
}
}
bool ServerRemotePlayer::addToInventory(InventoryItem *item)
{
infostream<<"Adding "<<item->getName()<<" into "<<getName()
<<"'s inventory"<<std::endl;
InventoryList *ilist = inventory.getList("main");
if(ilist == NULL)
return false;
// In creative mode, just delete the item
if(g_settings->getBool("creative_mode")){
return false;
}
// Skip if inventory has no free space
if(ilist->roomForItem(item) == false)
{
infostream<<"Player inventory has no free space"<<std::endl;
return false;
}
// Add to inventory
InventoryItem *leftover = ilist->addItem(item);
assert(!leftover);
m_inventory_not_sent = true;
return true;
}
void ServerRemotePlayer::addToInventoryLater(InventoryItem *item)
{
infostream<<"Adding (later) "<<item->getName()<<" into "<<getName()
<<"'s inventory"<<std::endl;
m_additional_items.push_back(item);
}
void ServerRemotePlayer::clearAddToInventoryLater()
{
for (std::vector<InventoryItem*>::iterator
i = m_additional_items.begin();
i != m_additional_items.end(); i++)
{
delete *i;
}
m_additional_items.clear();
}
void ServerRemotePlayer::completeAddToInventoryLater(u16 preferred_index)
{
InventoryList *ilist = inventory.getList("main");
if(ilist == NULL)
{
clearAddToInventoryLater();
return;
}
// In creative mode, just delete the items
if(g_settings->getBool("creative_mode"))
{
clearAddToInventoryLater();
return;
}
for (std::vector<InventoryItem*>::iterator
i = m_additional_items.begin();
i != m_additional_items.end(); i++)
{
InventoryItem *item = *i;
InventoryItem *leftover = item;
leftover = ilist->addItem(preferred_index, leftover);
leftover = ilist->addItem(leftover);
delete leftover;
}
m_additional_items.clear();
m_inventory_not_sent = true;
}
void ServerRemotePlayer::setHP(s16 hp_)
{
s16 oldhp = hp;
hp = hp_;
// FIXME: don't hardcode maximum HP, make configurable per object
if(hp < 0)
hp = 0;
else if(hp > 20)
hp = 20;
if(hp != oldhp)
m_hp_not_sent = true;
}
s16 ServerRemotePlayer::getHP()
{
return hp;
}
/*
RemotePlayer
*/
#ifndef SERVER
RemotePlayer::RemotePlayer(
IGameDef *gamedef,
scene::ISceneNode* parent,
IrrlichtDevice *device,
s32 id):
Player(gamedef),
scene::ISceneNode(parent, (device==NULL)?NULL:device->getSceneManager(), id),
m_text(NULL)
{
m_box = core::aabbox3d<f32>(-BS/2,0,-BS/2,BS/2,BS*2,BS/2);
if(parent != NULL && device != NULL)
{
// ISceneNode stores a member called SceneManager
scene::ISceneManager* mgr = SceneManager;
video::IVideoDriver* driver = mgr->getVideoDriver();
gui::IGUIEnvironment* gui = device->getGUIEnvironment();
// Add a text node for showing the name
wchar_t wname[1] = {0};
m_text = mgr->addTextSceneNode(gui->getBuiltInFont(),
wname, video::SColor(255,255,255,255), this);
m_text->setPosition(v3f(0, (f32)BS*2.1, 0));
// Attach a simple mesh to the player for showing an image
scene::SMesh *mesh = new scene::SMesh();
{ // Front
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
//buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
buf->getMaterial().setTexture(0, driver->getTexture(getTexturePath("player.png").c_str()));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
//buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
{ // Back
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
//buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
buf->getMaterial().setTexture(0, driver->getTexture(getTexturePath("player_back.png").c_str()));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
m_node = mgr->addMeshSceneNode(mesh, this);
mesh->drop();
m_node->setPosition(v3f(0,0,0));
}
}
RemotePlayer::~RemotePlayer()
{
if(SceneManager != NULL)
ISceneNode::remove();
}
void RemotePlayer::updateName(const char *name)
{
Player::updateName(name);
if(m_text != NULL)
{
wchar_t wname[PLAYERNAME_SIZE];
mbstowcs(wname, m_name, strlen(m_name)+1);
m_text->setText(wname);
}
}
void RemotePlayer::move(f32 dtime, Map &map, f32 pos_max_d)
{
m_pos_animation_time_counter += dtime;
m_pos_animation_counter += dtime;
v3f movevector = m_position - m_oldpos;
f32 moveratio;
if(m_pos_animation_time < 0.001)
moveratio = 1.0;
else
moveratio = m_pos_animation_counter / m_pos_animation_time;
if(moveratio > 1.5)
moveratio = 1.5;
m_showpos = m_oldpos + movevector * moveratio;
ISceneNode::setPosition(m_showpos);
}
#endif
#ifndef SERVER
/*
LocalPlayer

View File

@@ -174,172 +174,6 @@ class Player
};
/*
Player on the server
*/
#include "serverobject.h"
#include "content_object.h" // Object type IDs
class ServerRemotePlayer : public Player, public ServerActiveObject
{
public:
ServerRemotePlayer(ServerEnvironment *env);
ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 peer_id_,
const char *name_);
virtual ~ServerRemotePlayer();
virtual bool isLocal() const
{ return false; }
virtual void move(f32 dtime, Map &map, f32 pos_max_d)
{
}
virtual void setPosition(const v3f &position)
{
Player::setPosition(position);
ServerActiveObject::setBasePosition(position);
}
/* ServerActiveObject interface */
u8 getType() const
{return ACTIVEOBJECT_TYPE_PLAYER;}
virtual void setPos(v3f pos)
{
setPosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
m_last_good_position_age = 0;
}
virtual void moveTo(v3f pos, bool continuous)
{
setPosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
m_last_good_position_age = 0;
}
virtual std::string getDescription(){return getName();}
// Returns a reference
virtual InventoryItem* getWieldedItem();
virtual void damageWieldedItem(u16 amount);
// If all fits, eats item and returns true. Otherwise returns false.
virtual bool addToInventory(InventoryItem *item);
virtual void addToInventoryLater(InventoryItem *item);
void clearAddToInventoryLater();
void completeAddToInventoryLater(u16 preferred_index);
virtual void setHP(s16 hp_);
virtual s16 getHP();
v3f m_last_good_position;
float m_last_good_position_age;
std::vector<InventoryItem*> m_additional_items;
bool m_inventory_not_sent;
bool m_hp_not_sent;
private:
};
#ifndef SERVER
/*
All the other players on the client are these
*/
class RemotePlayer : public Player, public scene::ISceneNode
{
public:
RemotePlayer(
IGameDef *gamedef,
scene::ISceneNode* parent=NULL,
IrrlichtDevice *device=NULL,
s32 id=0);
virtual ~RemotePlayer();
/*
ISceneNode methods
*/
virtual void OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
virtual void render()
{
// Do nothing
}
virtual const core::aabbox3d<f32>& getBoundingBox() const
{
return m_box;
}
void setPosition(const v3f &position)
{
m_oldpos = m_showpos;
if(m_pos_animation_time < 0.001 || m_pos_animation_time > 1.0)
m_pos_animation_time = m_pos_animation_time_counter;
else
m_pos_animation_time = m_pos_animation_time * 0.9
+ m_pos_animation_time_counter * 0.1;
m_pos_animation_time_counter = 0;
m_pos_animation_counter = 0;
Player::setPosition(position);
//ISceneNode::setPosition(position);
}
virtual void setYaw(f32 yaw)
{
Player::setYaw(yaw);
ISceneNode::setRotation(v3f(0, -yaw, 0));
}
bool isLocal() const
{
return false;
}
void updateName(const char *name);
virtual void updateLight(u8 light_at_pos)
{
Player::updateLight(light_at_pos);
if(m_node == NULL)
return;
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
setMeshVerticesColor(m_node->getMesh(), color);
}
void move(f32 dtime, Map &map, f32 pos_max_d);
private:
scene::IMeshSceneNode *m_node;
scene::ITextSceneNode* m_text;
core::aabbox3d<f32> m_box;
v3f m_oldpos;
f32 m_pos_animation_counter;
f32 m_pos_animation_time;
f32 m_pos_animation_time_counter;
v3f m_showpos;
};
#endif // !SERVER
#ifndef SERVER
struct PlayerControl
{

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;
@@ -386,13 +446,24 @@ static int getenumfield(lua_State *L, int table,
return result;
}
static void setfloatfield(lua_State *L, int table,
const char *fieldname, float value)
{
lua_pushnumber(L, value);
if(table < 0)
table -= 1;
lua_setfield(L, table, fieldname);
}
/*
Inventory stuff
*/
static void inventory_set_list_from_lua(Inventory *inv, const char *name,
lua_State *L, int tableindex, IGameDef *gamedef)
lua_State *L, int tableindex, IGameDef *gamedef, int forcesize=-1)
{
if(tableindex < 0)
tableindex = lua_gettop(L) + 1 + tableindex;
// If nil, delete list
if(lua_isnil(L, tableindex)){
inv->deleteList(name);
@@ -411,10 +482,13 @@ static void inventory_set_list_from_lua(Inventory *inv, const char *name,
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
InventoryList *invlist = inv->addList(name, items.size());
int listsize = (forcesize != -1) ? forcesize : items.size();
InventoryList *invlist = inv->addList(name, listsize);
int index = 0;
for(std::list<std::string>::const_iterator
i = items.begin(); i != items.end(); i++){
if(forcesize != -1 && index == forcesize)
break;
const std::string &itemstring = *i;
InventoryItem *newitem = NULL;
if(itemstring != "")
@@ -424,6 +498,11 @@ static void inventory_set_list_from_lua(Inventory *inv, const char *name,
delete olditem;
index++;
}
while(forcesize != -1 && index < forcesize){
InventoryItem *olditem = invlist->changeItem(index, NULL);
delete olditem;
index++;
}
}
static void inventory_get_list_to_lua(Inventory *inv, const char *name,
@@ -446,15 +525,80 @@ static void inventory_get_list_to_lua(Inventory *inv, const char *name,
lua_pushvalue(L, table_insert);
lua_pushvalue(L, table);
if(item == NULL){
lua_pushnil(L);
lua_pushstring(L, "");
} else {
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));
}
}
/*
ToolDiggingProperties
*/
static ToolDiggingProperties read_tool_digging_properties(
lua_State *L, int table)
{
ToolDiggingProperties prop;
getfloatfield(L, table, "full_punch_interval", prop.full_punch_interval);
getfloatfield(L, table, "basetime", prop.basetime);
getfloatfield(L, table, "dt_weight", prop.dt_weight);
getfloatfield(L, table, "dt_crackiness", prop.dt_crackiness);
getfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness);
getfloatfield(L, table, "dt_cuttability", prop.dt_cuttability);
getfloatfield(L, table, "basedurability", prop.basedurability);
getfloatfield(L, table, "dd_weight", prop.dd_weight);
getfloatfield(L, table, "dd_crackiness", prop.dd_crackiness);
getfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness);
getfloatfield(L, table, "dd_cuttability", prop.dd_cuttability);
return prop;
}
static void set_tool_digging_properties(lua_State *L, int table,
const ToolDiggingProperties &prop)
{
setfloatfield(L, table, "full_punch_interval", prop.full_punch_interval);
setfloatfield(L, table, "basetime", prop.basetime);
setfloatfield(L, table, "dt_weight", prop.dt_weight);
setfloatfield(L, table, "dt_crackiness", prop.dt_crackiness);
setfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness);
setfloatfield(L, table, "dt_cuttability", prop.dt_cuttability);
setfloatfield(L, table, "basedurability", prop.basedurability);
setfloatfield(L, table, "dd_weight", prop.dd_weight);
setfloatfield(L, table, "dd_crackiness", prop.dd_crackiness);
setfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness);
setfloatfield(L, table, "dd_cuttability", prop.dd_cuttability);
}
static void push_tool_digging_properties(lua_State *L,
const ToolDiggingProperties &prop)
{
lua_newtable(L);
set_tool_digging_properties(L, -1, prop);
}
/*
ToolDefinition
*/
static ToolDefinition read_tool_definition(lua_State *L, int table)
{
ToolDefinition def;
getstringfield(L, table, "image", def.imagename);
def.properties = read_tool_digging_properties(L, table);
return def;
}
static void push_tool_definition(lua_State *L, const ToolDefinition &def)
{
lua_newtable(L);
lua_pushstring(L, def.imagename.c_str());
lua_setfield(L, -2, "image");
set_tool_digging_properties(L, -1, def.properties);
}
/*
EnumString definitions
*/
@@ -527,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
@@ -538,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);
@@ -619,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
@@ -660,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;
@@ -672,19 +818,7 @@ static int l_register_tool(lua_State *L)
IWritableToolDefManager *tooldef =
server->getWritableToolDefManager();
ToolDefinition def;
getstringfield(L, table, "image", def.imagename);
getfloatfield(L, table, "basetime", def.properties.basetime);
getfloatfield(L, table, "dt_weight", def.properties.dt_weight);
getfloatfield(L, table, "dt_crackiness", def.properties.dt_crackiness);
getfloatfield(L, table, "dt_crumbliness", def.properties.dt_crumbliness);
getfloatfield(L, table, "dt_cuttability", def.properties.dt_cuttability);
getfloatfield(L, table, "basedurability", def.properties.basedurability);
getfloatfield(L, table, "dd_weight", def.properties.dd_weight);
getfloatfield(L, table, "dd_crackiness", def.properties.dd_crackiness);
getfloatfield(L, table, "dd_crumbliness", def.properties.dd_crumbliness);
getfloatfield(L, table, "dd_cuttability", def.properties.dd_cuttability);
ToolDefinition def = read_tool_definition(L, table);
tooldef->registerTool(name, def);
return 0; /* number of results */
@@ -693,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;
@@ -734,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 */
}
@@ -742,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;
@@ -777,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);
@@ -982,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;
@@ -1029,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
@@ -1688,65 +1827,16 @@ class ObjectRef
return 0;
}
// get_wielded_itemstring(self)
static int l_get_wielded_itemstring(lua_State *L)
// get_wield_digging_properties(self)
static int l_get_wield_digging_properties(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
// Do it
InventoryItem *item = co->getWieldedItem();
if(item == NULL){
lua_pushnil(L);
return 1;
}
lua_pushstring(L, item->getItemString().c_str());
return 1;
}
// get_wielded_item(self)
static int l_get_wielded_item(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
// Do it
InventoryItem *item0 = co->getWieldedItem();
if(item0 == NULL){
lua_pushnil(L);
return 1;
}
if(std::string("MaterialItem") == item0->getName()){
MaterialItem *item = (MaterialItem*)item0;
lua_newtable(L);
lua_pushstring(L, "NodeItem");
lua_setfield(L, -2, "type");
lua_pushstring(L, item->getNodeName().c_str());
lua_setfield(L, -2, "name");
}
else if(std::string("CraftItem") == item0->getName()){
CraftItem *item = (CraftItem*)item0;
lua_newtable(L);
lua_pushstring(L, "CraftItem");
lua_setfield(L, -2, "type");
lua_pushstring(L, item->getSubName().c_str());
lua_setfield(L, -2, "name");
}
else if(std::string("ToolItem") == item0->getName()){
ToolItem *item = (ToolItem*)item0;
lua_newtable(L);
lua_pushstring(L, "ToolItem");
lua_setfield(L, -2, "type");
lua_pushstring(L, item->getToolName().c_str());
lua_setfield(L, -2, "name");
lua_pushstring(L, itos(item->getWear()).c_str());
lua_setfield(L, -2, "wear");
}
else{
errorstream<<"l_get_wielded_item: Unknown item name: \""
<<item0->getName()<<"\""<<std::endl;
lua_pushnil(L);
}
ToolDiggingProperties prop;
co->getWieldDiggingProperties(&prop);
push_tool_digging_properties(L, prop);
return 1;
}
@@ -1787,7 +1877,7 @@ class ObjectRef
// Return
lua_pushboolean(L, added);
if(!added)
lua_pushstring(L, "does not fit");
lua_pushstring(L, "failed to add item");
return 2;
} catch(SerializationError &e){
// Return
@@ -1957,7 +2047,7 @@ class ObjectRef
const char *name = lua_tostring(L, 2);
// Do it
inventory_set_list_from_lua(&player->inventory, name, L, 3,
player->getEnv()->getGameDef());
player->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE);
player->m_inventory_not_sent = true;
return 0;
}
@@ -1974,6 +2064,68 @@ class ObjectRef
return 1;
}
// get_wielded_itemstring(self)
static int l_get_wielded_itemstring(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerRemotePlayer *player = getplayer(ref);
if(player == NULL) return 0;
// Do it
InventoryItem *item = player->getWieldedItem();
if(item == NULL){
lua_pushnil(L);
return 1;
}
lua_pushstring(L, item->getItemString().c_str());
return 1;
}
// get_wielded_item(self)
static int l_get_wielded_item(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerRemotePlayer *player = getplayer(ref);
if(player == NULL) return 0;
// Do it
InventoryItem *item0 = player->getWieldedItem();
if(item0 == NULL){
lua_pushnil(L);
return 1;
}
if(std::string("MaterialItem") == item0->getName()){
MaterialItem *item = (MaterialItem*)item0;
lua_newtable(L);
lua_pushstring(L, "NodeItem");
lua_setfield(L, -2, "type");
lua_pushstring(L, item->getNodeName().c_str());
lua_setfield(L, -2, "name");
}
else if(std::string("CraftItem") == item0->getName()){
CraftItem *item = (CraftItem*)item0;
lua_newtable(L);
lua_pushstring(L, "CraftItem");
lua_setfield(L, -2, "type");
lua_pushstring(L, item->getSubName().c_str());
lua_setfield(L, -2, "name");
}
else if(std::string("ToolItem") == item0->getName()){
ToolItem *item = (ToolItem*)item0;
lua_newtable(L);
lua_pushstring(L, "ToolItem");
lua_setfield(L, -2, "type");
lua_pushstring(L, item->getToolName().c_str());
lua_setfield(L, -2, "name");
lua_pushstring(L, itos(item->getWear()).c_str());
lua_setfield(L, -2, "wear");
}
else{
errorstream<<"l_get_wielded_item: Unknown item name: \""
<<item0->getName()<<"\""<<std::endl;
lua_pushnil(L);
}
return 1;
}
public:
ObjectRef(ServerActiveObject *object):
m_object(object)
@@ -2044,8 +2196,7 @@ const luaL_reg ObjectRef::methods[] = {
method(ObjectRef, moveto),
method(ObjectRef, punch),
method(ObjectRef, right_click),
method(ObjectRef, get_wielded_itemstring),
method(ObjectRef, get_wielded_item),
method(ObjectRef, get_wield_digging_properties),
method(ObjectRef, damage_wielded_item),
method(ObjectRef, add_to_inventory),
method(ObjectRef, add_to_inventory_later),
@@ -2061,6 +2212,8 @@ const luaL_reg ObjectRef::methods[] = {
method(ObjectRef, get_player_name),
method(ObjectRef, inventory_set_list),
method(ObjectRef, inventory_get_list),
method(ObjectRef, get_wielded_itemstring),
method(ObjectRef, get_wielded_item),
{0,0}
};
@@ -2383,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);
@@ -2463,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
@@ -2541,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)
@@ -2574,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
}
}
@@ -2599,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)
@@ -2609,6 +2780,15 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
return positioning_handled_by_some;
}
void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player)
{
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "creative_inventory");
luaL_checktype(L, -1, LUA_TTABLE);
inventory_set_list_from_lua(&player->inventory, "main", L, -1,
player->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE);
}
/*
craftitem
*/
@@ -2712,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;
@@ -2736,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;
@@ -2760,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;
@@ -2790,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
}
}
@@ -2825,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
}
}
@@ -2860,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
}
}
@@ -2895,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
}
}
@@ -2921,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
}
}
@@ -3124,9 +3304,9 @@ void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
script_error(L, "error running function 'on_step': %s\n", lua_tostring(L, -1));
}
// Calls entity:on_punch(ObjectRef puncher)
// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch)
void scriptapi_luaentity_punch(lua_State *L, u16 id,
ServerActiveObject *puncher)
ServerActiveObject *puncher, float time_from_last_punch)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
@@ -3144,8 +3324,9 @@ void scriptapi_luaentity_punch(lua_State *L, u16 id,
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self
objectref_get_or_create(L, puncher); // Clicker reference
lua_pushnumber(L, time_from_last_punch);
// Call with 2 arguments, 0 results
if(lua_pcall(L, 2, 0, 0))
if(lua_pcall(L, 3, 0, 0))
script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1));
}

View File

@@ -31,8 +31,11 @@ typedef struct lua_State lua_State;
struct LuaEntityProperties;
struct PointedThing;
//class IGameDef;
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);
@@ -60,6 +63,7 @@ void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp);
/* misc */
void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player);
bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player);
void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player);
/* craftitem */
void scriptapi_add_craftitem(lua_State *L, const char *name);
@@ -83,7 +87,7 @@ void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
LuaEntityProperties *prop);
void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime);
void scriptapi_luaentity_punch(lua_State *L, u16 id,
ServerActiveObject *puncher);
ServerActiveObject *puncher, float time_from_last_punch);
void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
ServerActiveObject *clicker);

View File

@@ -33,7 +33,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "servercommand.h"
#include "filesys.h"
#include "content_mapnode.h"
#include "content_craft.h"
#include "content_nodemeta.h"
#include "mapblock.h"
#include "serverobject.h"
@@ -48,6 +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 "mods.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@@ -749,105 +749,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
}
void RemoteClient::SendObjectData(
Server *server,
float dtime,
core::map<v3s16, bool> &stepped_blocks
)
{
DSTACK(__FUNCTION_NAME);
// Can't send anything without knowing version
if(serialization_version == SER_FMT_VER_INVALID)
{
infostream<<"RemoteClient::SendObjectData(): Not sending, no version."
<<std::endl;
return;
}
/*
Send a TOCLIENT_OBJECTDATA packet.
Sent as unreliable.
u16 command
u16 number of player positions
for each player:
u16 peer_id
v3s32 position*100
v3s32 speed*100
s32 pitch*100
s32 yaw*100
u16 count of blocks
for each block:
block objects
*/
std::ostringstream os(std::ios_base::binary);
u8 buf[12];
// Write command
writeU16(buf, TOCLIENT_OBJECTDATA);
os.write((char*)buf, 2);
/*
Get and write player data
*/
// Get connected players
core::list<Player*> players = server->m_env->getPlayers(true);
// Write player count
u16 playercount = players.size();
writeU16(buf, playercount);
os.write((char*)buf, 2);
core::list<Player*>::Iterator i;
for(i = players.begin();
i != players.end(); i++)
{
Player *player = *i;
v3f pf = player->getPosition();
v3f sf = player->getSpeed();
v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
s32 pitch_i (player->getPitch() * 100);
s32 yaw_i (player->getYaw() * 100);
writeU16(buf, player->peer_id);
os.write((char*)buf, 2);
writeV3S32(buf, position_i);
os.write((char*)buf, 12);
writeV3S32(buf, speed_i);
os.write((char*)buf, 12);
writeS32(buf, pitch_i);
os.write((char*)buf, 4);
writeS32(buf, yaw_i);
os.write((char*)buf, 4);
}
/*
Get and write object data (dummy, for compatibility)
*/
// Write block count
writeU16(buf, 0);
os.write((char*)buf, 2);
/*
Send data
*/
//infostream<<"Server: Sending object data to "<<peer_id<<std::endl;
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as unreliable
server->m_con.Send(peer_id, 0, data, false);
}
void RemoteClient::GotBlock(v3s16 p)
{
if(m_blocks_sending.find(p) != NULL)
@@ -932,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
*/
@@ -1060,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;
@@ -1077,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);
@@ -1090,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);
}
}
@@ -1382,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;
@@ -1430,6 +1258,11 @@ void Server::AsyncRunStep()
player->m_last_good_position_age = 0;
}
/*
Handle player HPs (die if hp=0)
*/
HandlePlayerHP(player, 0);
/*
Send player inventories and HPs if necessary
*/
@@ -1440,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);
}
}
}
@@ -1541,6 +1383,12 @@ void Server::AsyncRunStep()
i.atEnd() == false; i++)
{
RemoteClient *client = i.getNode()->getValue();
// If definitions and textures have not been sent, don't
// send objects either
if(!client->definitions_sent)
continue;
Player *player = m_env->getPlayer(client->peer_id);
if(player==NULL)
{
@@ -1679,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
@@ -1908,25 +1756,6 @@ void Server::AsyncRunStep()
}
/*
Send object positions
*/
{
float &counter = m_objectdata_timer;
counter += dtime;
if(counter >= g_settings->getFloat("objectdata_interval"))
{
JMutexAutoLock lock1(m_env_mutex);
JMutexAutoLock lock2(m_con_mutex);
//ScopeProfiler sp(g_profiler, "Server: sending player positions");
SendObjectData(counter);
counter = 0.0;
}
}
/*
Trigger emergethread (it somehow gets to a non-triggered but
bysy state sometimes)
@@ -2121,7 +1950,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
SendAccessDenied(m_con, peer_id, std::wstring(
L"Your client's version is not supported.\n"
L"Server version is ")
+ narrow_to_wide(VERSION_STRING) + L"."
+ narrow_to_wide(VERSION_STRING) + L",\n"
+ L"server's PROTOCOL_VERSION is "
+ narrow_to_wide(itos(PROTOCOL_VERSION))
+ L", client's PROTOCOL_VERSION is "
+ narrow_to_wide(itos(net_proto_version))
);
return;
}
@@ -2171,20 +2004,33 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
password[PASSWORD_SIZE-1] = 0;
}
std::string checkpwd;
if(m_authmanager.exists(playername))
// Add player to auth manager
if(m_authmanager.exists(playername) == false)
{
checkpwd = m_authmanager.getPassword(playername);
std::wstring default_password =
narrow_to_wide(g_settings->get("default_password"));
std::string translated_default_password =
translatePassword(playername, default_password);
// If default_password is empty, allow any initial password
if (default_password.length() == 0)
translated_default_password = password;
infostream<<"Server: adding player "<<playername
<<" to auth manager"<<std::endl;
m_authmanager.add(playername);
m_authmanager.setPassword(playername, translated_default_password);
m_authmanager.setPrivs(playername,
stringToPrivs(g_settings->get("default_privs")));
m_authmanager.save();
}
else
{
checkpwd = g_settings->get("default_password");
}
std::string checkpwd = m_authmanager.getPassword(playername);
/*infostream<<"Server: Client gave password '"<<password
<<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
if(password != checkpwd && m_authmanager.exists(playername))
if(password != checkpwd)
{
infostream<<"Server: peer_id="<<peer_id
<<": supplied invalid password for "
@@ -2193,23 +2039,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
return;
}
// Add player to auth manager
if(m_authmanager.exists(playername) == false)
{
infostream<<"Server: adding player "<<playername
<<" to auth manager"<<std::endl;
m_authmanager.add(playername);
m_authmanager.setPassword(playername, checkpwd);
m_authmanager.setPrivs(playername,
stringToPrivs(g_settings->get("default_privs")));
m_authmanager.save();
}
// Enforce user limit.
// Don't enforce for users that have some admin right
if(m_clients.size() >= g_settings->getU16("max_users") &&
(m_authmanager.getPrivs(playername)
& (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 &&
& (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
playername != g_settings->get("name"))
{
SendAccessDenied(m_con, peer_id, L"Too many users.");
@@ -2217,7 +2051,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
// Get player
Player *player = emergePlayer(playername, password, peer_id);
ServerRemotePlayer *player = emergePlayer(playername, peer_id);
// If failed, cancel
if(player == NULL)
@@ -2275,12 +2109,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
SendTextures(peer_id);
// Send player info to all players
SendPlayerInfos();
//SendPlayerInfos();
// Send inventory to player
UpdateCrafting(peer_id);
SendInventory(peer_id);
// Send player items to all players
SendPlayerItems();
@@ -2296,6 +2130,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
m_con.Send(peer_id, 0, data, true);
}
// Now the client should know about everything
getClient(peer_id)->definitions_sent = true;
// Send information about server to player in chat
SendChatMessage(peer_id, getStatusString());
@@ -2474,7 +2311,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
else if(command == TOSERVER_SIGNNODETEXT)
{
if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
return;
/*
u16 command
@@ -2655,7 +2492,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Disallow moving items in elsewhere than player's inventory
// if not allowed to build
if((getPlayerPrivs(player) & PRIV_BUILD) == 0
if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
&& (ma->from_inv != "current_player"
|| ma->to_inv != "current_player"))
{
@@ -2721,7 +2558,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
IDropAction *da = (IDropAction*)a;
// Disallow dropping items if not allowed to build
if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
{
delete a;
return;
@@ -2973,10 +2810,15 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if(player->hp != 0)
return;
srp->m_respawn_active = false;
RespawnPlayer(player);
actionstream<<player->getName()<<" respawns at "
<<PP(player->getPosition()/BS)<<std::endl;
// ActiveObject is added to environment in AsyncRunStep after
// the previous addition has been succesfully removed
}
else if(command == TOSERVER_INTERACT)
{
@@ -3063,7 +2905,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
/*
Make sure the player is allowed to do it
*/
bool build_priv = (getPlayerPrivs(player) & PRIV_BUILD) != 0;
bool build_priv = (getPlayerPrivs(player) & PRIV_INTERACT) != 0;
if(!build_priv)
{
infostream<<"Ignoring interaction from player "<<player->getName()
@@ -3939,64 +3781,6 @@ void Server::SendCraftItemDef(con::Connection &con, u16 peer_id,
Non-static send methods
*/
void Server::SendObjectData(float dtime)
{
DSTACK(__FUNCTION_NAME);
core::map<v3s16, bool> stepped_blocks;
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
i.atEnd() == false; i++)
{
u16 peer_id = i.getNode()->getKey();
RemoteClient *client = i.getNode()->getValue();
assert(client->peer_id == peer_id);
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
client->SendObjectData(this, dtime, stepped_blocks);
}
}
void Server::SendPlayerInfos()
{
DSTACK(__FUNCTION_NAME);
//JMutexAutoLock envlock(m_env_mutex);
// Get connected players
core::list<Player*> players = m_env->getPlayers(true);
u32 player_count = players.getSize();
u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
SharedBuffer<u8> data(datasize);
writeU16(&data[0], TOCLIENT_PLAYERINFO);
u32 start = 2;
core::list<Player*>::Iterator i;
for(i = players.begin();
i != players.end(); i++)
{
Player *player = *i;
/*infostream<<"Server sending player info for player with "
"peer_id="<<player->peer_id<<std::endl;*/
writeU16(&data[start], player->peer_id);
memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
start += 2+PLAYERNAME_SIZE;
}
//JMutexAutoLock conlock(m_con_mutex);
// Send as reliable
m_con.SendToAll(0, data, true);
}
void Server::SendInventory(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
@@ -4129,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)
@@ -4345,6 +4130,11 @@ void Server::SendBlocks(float dtime)
RemoteClient *client = i.getNode()->getValue();
assert(client->peer_id == i.getNode()->getKey());
// If definitions and textures have not been sent, don't
// send MapBlocks either
if(!client->definitions_sent)
continue;
total_sending += client->SendingCount();
if(client->serialization_version == SER_FMT_VER_INVALID)
@@ -4517,37 +4307,46 @@ void Server::SendTextures(u16 peer_id)
void Server::HandlePlayerHP(Player *player, s16 damage)
{
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
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));
}
else
{
RespawnPlayer(player);
}
RespawnPlayer(player);
}
}
@@ -4678,6 +4477,22 @@ std::wstring Server::getStatusString()
return os.str();
}
void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
{
// Add player to auth manager
if(m_authmanager.exists(name) == false)
{
infostream<<"Server: adding player "<<name
<<" to auth manager"<<std::endl;
m_authmanager.add(name);
m_authmanager.setPrivs(name,
stringToPrivs(g_settings->get("default_privs")));
}
// Change password and save
m_authmanager.setPassword(name, translatePassword(name, password));
m_authmanager.save();
}
// Saves g_settings to configpath given at initialization
void Server::saveConfig()
{
@@ -4813,12 +4628,13 @@ v3f findSpawnPos(ServerMap &map)
return intToFloat(nodepos, BS);
}
Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
{
/*
Try to get an existing player
*/
Player *player = m_env->getPlayer(name);
ServerRemotePlayer *player =
static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
if(player != NULL)
{
// If player is already connected, cancel
@@ -4839,7 +4655,8 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id
player->inventory_backup = new Inventory();
*(player->inventory_backup) = player->inventory;
// Set creative inventory
craft_set_creative_inventory(player, this);
player->resetInventory();
scriptapi_get_creative_inventory(m_lua, player);
}
return player;
@@ -4859,12 +4676,6 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id
Create a new player
*/
{
// Add authentication stuff
m_authmanager.add(name);
m_authmanager.setPassword(name, password);
m_authmanager.setPrivs(name,
stringToPrivs(g_settings->get("default_privs")));
/* Set player position */
infostream<<"Server: Finding spawn place for player \""
@@ -4889,7 +4700,8 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id
player->inventory_backup = new Inventory();
*(player->inventory_backup) = player->inventory;
// Set creative inventory
craft_set_creative_inventory(player, this);
player->resetInventory();
scriptapi_get_creative_inventory(m_lua, player);
}
return player;
@@ -4949,10 +4761,12 @@ void Server::handlePeerChange(PeerChange &c)
obj->m_known_by_count--;
}
ServerRemotePlayer* player =
static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
// Collect information about leaving in chat
std::wstring message;
{
Player *player = m_env->getPlayer(c.peer_id);
if(player != NULL)
{
std::wstring name = narrow_to_wide(player->getName());
@@ -4963,21 +4777,19 @@ void Server::handlePeerChange(PeerChange &c)
message += L" (timed out)";
}
}
/*// Delete player
{
m_env->removePlayer(c.peer_id);
}*/
// Remove from environment
if(player != NULL)
player->m_removed = true;
// Set player client disconnected
if(player != NULL)
player->peer_id = 0;
/*
Print out action
*/
{
Player *player = m_env->getPlayer(c.peer_id);
if(player != NULL)
player->peer_id = 0;
/*
Print out action
*/
if(player != NULL)
{
std::ostringstream os(std::ios_base::binary);
@@ -5009,10 +4821,11 @@ void Server::handlePeerChange(PeerChange &c)
m_clients.remove(c.peer_id);
// Send player info to all remaining clients
SendPlayerInfos();
//SendPlayerInfos();
// Send leave chat message to all remaining clients
BroadcastChatMessage(message);
if(message.length() != 0)
BroadcastChatMessage(message);
} // PEER_REMOVED
else

View File

@@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "ban.h"
#include "gamedef.h"
#include "serialization.h" // For SER_FMT_VER_INVALID
#include "serverremoteplayer.h"
struct LuaState;
typedef struct lua_State lua_State;
class IWritableToolDefManager;
@@ -248,6 +249,8 @@ class RemoteClient
// Version is stored in here after INIT before INIT2
u8 pending_serialization_version;
bool definitions_sent;
RemoteClient():
m_time_from_building(9999),
m_excess_gotblocks(0)
@@ -256,6 +259,7 @@ class RemoteClient
serialization_version = SER_FMT_VER_INVALID;
net_proto_version = 0;
pending_serialization_version = SER_FMT_VER_INVALID;
definitions_sent = false;
m_nearest_unsent_d = 0;
m_nearest_unsent_reset_timer = 0.0;
m_nothing_to_send_counter = 0;
@@ -273,17 +277,6 @@ class RemoteClient
void GetNextBlocks(Server *server, float dtime,
core::array<PrioritySortedBlockTransfer> &dest);
/*
Connection and environment should be locked when this is called.
steps() objects of blocks not found in active_blocks, then
adds those blocks to active_blocks
*/
void SendObjectData(
Server *server,
float dtime,
core::map<v3s16, bool> &stepped_blocks
);
void GotBlock(v3s16 p);
void SentBlock(v3s16 p);
@@ -456,6 +449,10 @@ class Server : public con::PeerHandler, public MapEventReceiver,
dstream<<"WARNING: Auth not found for "<<name<<std::endl;
}
}
// Changes a player's password, password must be given as plaintext
// If the player doesn't exist, a new entry is added to the auth manager
void setPlayerPassword(const std::string &name, const std::wstring &password);
// Saves g_settings to configpath given at initialization
void saveConfig();
@@ -537,8 +534,6 @@ class Server : public con::PeerHandler, public MapEventReceiver,
*/
// Envlock and conlock should be locked when calling these
void SendObjectData(float dtime);
void SendPlayerInfos();
void SendInventory(u16 peer_id);
// send wielded item info about player to all
void SendWieldedItem(const Player *player);
@@ -591,12 +586,11 @@ class Server : public con::PeerHandler, public MapEventReceiver,
/*
Get a player from memory or creates one.
If player is already connected, return NULL
The password is not checked here - it is only used to
set the password if a new player is created.
Does not verify/modify auth info and password.
Call with env and con locked.
*/
Player *emergePlayer(const char *name, const char *password, u16 peer_id);
ServerRemotePlayer *emergePlayer(const char *name, u16 peer_id);
// Locks environment and connection by its own
struct PeerChange;

View File

@@ -281,6 +281,58 @@ void cmd_banunban(std::wostringstream &os, ServerCommandContext *ctx)
}
}
void cmd_setclearpassword(std::wostringstream &os,
ServerCommandContext *ctx)
{
if((ctx->privs & PRIV_PASSWORD) == 0)
{
os<<L"-!- You don't have permission to do that";
return;
}
std::string playername;
std::wstring password;
if(ctx->parms[0] == L"setpassword")
{
if(ctx->parms.size() != 3)
{
os<<L"-!- Missing parameter";
return;
}
playername = wide_to_narrow(ctx->parms[1]);
password = ctx->parms[2];
actionstream<<ctx->player->getName()<<" sets password of "
<<playername<<std::endl;
}
else
{
// clearpassword
if(ctx->parms.size() != 2)
{
os<<L"-!- Missing parameter";
return;
}
playername = wide_to_narrow(ctx->parms[1]);
password = L"";
actionstream<<ctx->player->getName()<<" clears password of"
<<playername<<std::endl;
}
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";
}
void cmd_clearobjects(std::wostringstream &os,
ServerCommandContext *ctx)
{
@@ -322,9 +374,9 @@ std::wstring processServerCommand(ServerCommandContext *ctx)
if(ctx->parms.size() == 0 || ctx->parms[0] == L"help")
{
os<<L"-!- Available commands: ";
os<<L"status privs ";
os<<L"me status privs";
if(privs & PRIV_SERVER)
os<<L"shutdown setting ";
os<<L" shutdown setting clearobjects";
if(privs & PRIV_SETTIME)
os<<L" time";
if(privs & PRIV_TELEPORT)
@@ -333,6 +385,8 @@ std::wstring processServerCommand(ServerCommandContext *ctx)
os<<L" grant revoke";
if(privs & PRIV_BAN)
os<<L" ban unban";
if(privs & PRIV_PASSWORD)
os<<L" setpassword clearpassword";
}
else if(ctx->parms[0] == L"status")
cmd_status(os, ctx);
@@ -350,6 +404,8 @@ std::wstring processServerCommand(ServerCommandContext *ctx)
cmd_teleport(os, ctx);
else if(ctx->parms[0] == L"ban" || ctx->parms[0] == L"unban")
cmd_banunban(os, ctx);
else if(ctx->parms[0] == L"setpassword" || ctx->parms[0] == L"clearpassword")
cmd_setclearpassword(os, ctx);
else if(ctx->parms[0] == L"me")
cmd_me(os, ctx);
else if(ctx->parms[0] == L"clearobjects")

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

@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverobject.h"
#include <fstream>
#include "inventory.h"
#include "tooldef.h"
ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos):
ActiveObject(0),
@@ -37,10 +38,6 @@ ServerActiveObject::~ServerActiveObject()
{
}
void ServerActiveObject::addedToEnvironment()
{
}
ServerActiveObject* ServerActiveObject::create(u8 type,
ServerEnvironment *env, u16 id, v3f pos,
const std::string &data)
@@ -70,5 +67,10 @@ void ServerActiveObject::registerType(u16 type, Factory f)
m_types.insert(type, f);
}
void ServerActiveObject::getWieldDiggingProperties(ToolDiggingProperties *dst)
{
*dst = ToolDiggingProperties();
}

View File

@@ -43,6 +43,7 @@ Some planning
class ServerEnvironment;
class InventoryItem;
class Player;
struct ToolDiggingProperties;
class ServerActiveObject : public ActiveObject
{
@@ -54,8 +55,17 @@ class ServerActiveObject : public ActiveObject
ServerActiveObject(ServerEnvironment *env, v3f pos);
virtual ~ServerActiveObject();
// Call after id has been set and has been inserted in environment
virtual void addedToEnvironment();
// Called after id has been set and has been inserted in environment
virtual void addedToEnvironment(){};
// Called before removing from environment
virtual void removingFromEnvironment(){};
// Returns true if object's deletion is the job of the
// environment
virtual bool environmentDeletes() const
{ return true; }
virtual bool unlimitedTransferDistance() const
{ return false; }
// Create a certain type of ServerActiveObject
static ServerActiveObject* create(u8 type,
@@ -110,25 +120,36 @@ class ServerActiveObject : public ActiveObject
when it is created (converted from static to active - actually
the data is the static form)
*/
virtual std::string getStaticData(){return "";}
virtual std::string getStaticData()
{
assert(isStaticAllowed());
return "";
}
/*
Return false in here to never save and instead remove object
on unload. getStaticData() will not be called in that case.
*/
virtual bool isStaticAllowed() const
{return true;}
virtual void punch(ServerActiveObject *puncher){}
virtual void rightClick(ServerActiveObject *clicker){}
// Returns a reference
virtual InventoryItem* getWieldedItem()
{ return NULL; }
// time_from_last_punch is used for lessening damage if punching fast
virtual void punch(ServerActiveObject *puncher,
float time_from_last_punch=1000000)
{}
virtual void rightClick(ServerActiveObject *clicker)
{}
virtual void getWieldDiggingProperties(ToolDiggingProperties *dst);
virtual void damageWieldedItem(u16 amount)
{}
{}
// If all fits, eats item and returns true. Otherwise returns false.
virtual bool addToInventory(InventoryItem *item)
{return false;}
{ return false; }
virtual void addToInventoryLater(InventoryItem *item)
{}
{}
virtual void setHP(s16 hp)
{}
{}
virtual s16 getHP()
{return 0;}
{ return 0; }
/*
Number of players which know about this object. Object won't be
@@ -149,12 +170,13 @@ class ServerActiveObject : public ActiveObject
bool m_removed;
/*
This is set to true when a block should be removed from the active
This is set to true when an object should be removed from the active
object list but couldn't be removed because the id has to be
reserved for some client.
The environment checks this periodically. If this is true and also
m_known_by_count is true,
m_known_by_count is true, object is deleted from the active object
list.
*/
bool m_pending_deactivation;

316
src/serverremoteplayer.cpp Normal file
View File

@@ -0,0 +1,316 @@
/*
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 "serverremoteplayer.h"
#include "main.h" // For g_settings
#include "settings.h"
#include "log.h"
#include "gamedef.h"
#include "tooldef.h"
#include "environment.h"
#include "materials.h"
ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env):
Player(env->getGameDef()),
ServerActiveObject(env, v3f(0,0,0)),
m_last_good_position(0,0,0),
m_last_good_position_age(0),
m_additional_items(),
m_inventory_not_sent(false),
m_hp_not_sent(false),
m_respawn_active(false),
m_is_in_environment(false),
m_position_not_sent(false)
{
}
ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 peer_id_,
const char *name_):
Player(env->getGameDef()),
ServerActiveObject(env, pos_),
m_inventory_not_sent(false),
m_hp_not_sent(false),
m_is_in_environment(false),
m_position_not_sent(false)
{
setPosition(pos_);
peer_id = peer_id_;
updateName(name_);
}
ServerRemotePlayer::~ServerRemotePlayer()
{
clearAddToInventoryLater();
}
void ServerRemotePlayer::setPosition(const v3f &position)
{
Player::setPosition(position);
ServerActiveObject::setBasePosition(position);
m_position_not_sent = true;
}
InventoryItem* ServerRemotePlayer::getWieldedItem()
{
InventoryList *list = inventory.getList("main");
if (list)
return list->getItem(m_selected_item);
return NULL;
}
/* ServerActiveObject interface */
void ServerRemotePlayer::addedToEnvironment()
{
assert(!m_is_in_environment);
m_is_in_environment = true;
}
void ServerRemotePlayer::removingFromEnvironment()
{
assert(m_is_in_environment);
m_is_in_environment = false;
}
bool ServerRemotePlayer::unlimitedTransferDistance() const
{
return g_settings->getBool("unlimited_player_transfer_distance");
}
void ServerRemotePlayer::step(float dtime, bool send_recommended)
{
if(send_recommended == false)
return;
if(m_position_not_sent)
{
m_position_not_sent = false;
std::ostringstream os(std::ios::binary);
// command (0 = update position)
writeU8(os, 0);
// pos
writeV3F1000(os, getPosition());
// yaw
writeF1000(os, getYaw());
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
std::string ServerRemotePlayer::getClientInitializationData()
{
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
// name
os<<serializeString(getName());
// pos
writeV3F1000(os, getPosition());
// yaw
writeF1000(os, getYaw());
return os.str();
}
std::string ServerRemotePlayer::getStaticData()
{
assert(0);
return "";
}
void ServerRemotePlayer::punch(ServerActiveObject *puncher,
float time_from_last_punch)
{
if(!puncher)
return;
// No effect if PvP disabled
if(g_settings->getBool("enable_pvp") == false){
if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER)
return;
}
// "Material" properties of a player
MaterialProperties mp;
mp.diggability = DIGGABLE_NORMAL;
mp.crackiness = -0.5;
mp.cuttability = 0.5;
ToolDiggingProperties tp;
puncher->getWieldDiggingProperties(&tp);
HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch);
setHP(getHP() - hitprop.hp);
puncher->damageWieldedItem(hitprop.wear);
{
std::ostringstream os(std::ios::binary);
// command (1 = punched)
writeU8(os, 1);
// damage
writeS16(os, hitprop.hp);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
void ServerRemotePlayer::rightClick(ServerActiveObject *clicker)
{
}
void ServerRemotePlayer::setPos(v3f pos)
{
setPosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
m_last_good_position_age = 0;
}
void ServerRemotePlayer::moveTo(v3f pos, bool continuous)
{
setPosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
m_last_good_position_age = 0;
}
void ServerRemotePlayer::getWieldDiggingProperties(ToolDiggingProperties *dst)
{
IGameDef *gamedef = m_env->getGameDef();
IToolDefManager *tdef = gamedef->tdef();
InventoryItem *item = getWieldedItem();
if(item == NULL || std::string(item->getName()) != "ToolItem"){
*dst = ToolDiggingProperties();
return;
}
ToolItem *titem = (ToolItem*)item;
*dst = tdef->getDiggingProperties(titem->getToolName());
}
void ServerRemotePlayer::damageWieldedItem(u16 amount)
{
infostream<<"Damaging "<<getName()<<"'s wielded item for amount="
<<amount<<std::endl;
InventoryList *list = inventory.getList("main");
if(!list)
return;
InventoryItem *item = list->getItem(m_selected_item);
if(item && (std::string)item->getName() == "ToolItem"){
ToolItem *titem = (ToolItem*)item;
bool weared_out = titem->addWear(amount);
if(weared_out)
list->deleteItem(m_selected_item);
}
}
bool ServerRemotePlayer::addToInventory(InventoryItem *item)
{
infostream<<"Adding "<<item->getName()<<" into "<<getName()
<<"'s inventory"<<std::endl;
InventoryList *ilist = inventory.getList("main");
if(ilist == NULL)
return false;
// In creative mode, just delete the item
if(g_settings->getBool("creative_mode")){
return false;
}
// Skip if inventory has no free space
if(ilist->roomForItem(item) == false)
{
infostream<<"Player inventory has no free space"<<std::endl;
return false;
}
// Add to inventory
InventoryItem *leftover = ilist->addItem(item);
assert(!leftover);
m_inventory_not_sent = true;
return true;
}
void ServerRemotePlayer::addToInventoryLater(InventoryItem *item)
{
infostream<<"Adding (later) "<<item->getName()<<" into "<<getName()
<<"'s inventory"<<std::endl;
m_additional_items.push_back(item);
}
void ServerRemotePlayer::clearAddToInventoryLater()
{
for (std::vector<InventoryItem*>::iterator
i = m_additional_items.begin();
i != m_additional_items.end(); i++)
{
delete *i;
}
m_additional_items.clear();
}
void ServerRemotePlayer::completeAddToInventoryLater(u16 preferred_index)
{
InventoryList *ilist = inventory.getList("main");
if(ilist == NULL)
{
clearAddToInventoryLater();
return;
}
// In creative mode, just delete the items
if(g_settings->getBool("creative_mode"))
{
clearAddToInventoryLater();
return;
}
for (std::vector<InventoryItem*>::iterator
i = m_additional_items.begin();
i != m_additional_items.end(); i++)
{
InventoryItem *item = *i;
InventoryItem *leftover = item;
leftover = ilist->addItem(preferred_index, leftover);
leftover = ilist->addItem(leftover);
delete leftover;
}
m_additional_items.clear();
m_inventory_not_sent = true;
}
void ServerRemotePlayer::setHP(s16 hp_)
{
s16 oldhp = hp;
// FIXME: don't hardcode maximum HP, make configurable per object
if(hp_ < 0)
hp_ = 0;
else if(hp_ > 20)
hp_ = 20;
hp = hp_;
if(hp != oldhp)
m_hp_not_sent = true;
}
s16 ServerRemotePlayer::getHP()
{
return hp;
}

102
src/serverremoteplayer.h Normal file
View File

@@ -0,0 +1,102 @@
/*
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 SERVERREMOTEPLAYER_HEADER
#define SERVERREMOTEPLAYER_HEADER
#include "player.h"
#include "serverobject.h"
#include "content_object.h" // Object type IDs
/*
Player on the server
*/
class ServerRemotePlayer : public Player, public ServerActiveObject
{
public:
ServerRemotePlayer(ServerEnvironment *env);
ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 peer_id_,
const char *name_);
virtual ~ServerRemotePlayer();
virtual bool isLocal() const
{ return false; }
virtual void move(f32 dtime, Map &map, f32 pos_max_d)
{
}
virtual void setPosition(const v3f &position);
// Returns a reference
virtual InventoryItem* getWieldedItem();
/* ServerActiveObject interface */
u8 getType() const
{return ACTIVEOBJECT_TYPE_PLAYER;}
// Called after id has been set and has been inserted in environment
void addedToEnvironment();
// Called before removing from environment
void removingFromEnvironment();
bool environmentDeletes() const
{ return false; }
virtual bool unlimitedTransferDistance() const;
bool isStaticAllowed() const
{ return false; }
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
void rightClick(ServerActiveObject *clicker);
void setPos(v3f pos);
void moveTo(v3f pos, bool continuous);
virtual std::string getDescription(){return getName();}
virtual void getWieldDiggingProperties(ToolDiggingProperties *dst);
virtual void damageWieldedItem(u16 amount);
// If all fits, eats item and returns true. Otherwise returns false.
virtual bool addToInventory(InventoryItem *item);
virtual void addToInventoryLater(InventoryItem *item);
void clearAddToInventoryLater();
void completeAddToInventoryLater(u16 preferred_index);
virtual void setHP(s16 hp_);
virtual s16 getHP();
v3f m_last_good_position;
float m_last_good_position_age;
std::vector<InventoryItem*> m_additional_items;
bool m_inventory_not_sent;
bool m_hp_not_sent;
bool m_respawn_active;
bool m_is_in_environment;
private:
bool m_position_not_sent;
};
#endif

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
@@ -332,7 +333,7 @@ class TextureSource : public IWritableTextureSource
// Gets a separate texture
video::ITexture* getTextureRaw(const std::string &name)
{
AtlasPointer ap = getTexture(name);
AtlasPointer ap = getTexture(name + "^[forcesingle");
return ap.atlas;
}
@@ -906,10 +907,14 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
for(u32 j=0; j<xwise_tiling; j++)
{
// Copy the copy to the atlas
img2->copyToWithAlpha(atlas_img,
/*img2->copyToWithAlpha(atlas_img,
pos_in_atlas + v2s32(j*dim.Width,0),
core::rect<s32>(v2s32(0,0), dim),
video::SColor(255,255,255,255),
NULL);*/
img2->copyTo(atlas_img,
pos_in_atlas + v2s32(j*dim.Width,0),
core::rect<s32>(v2s32(0,0), dim),
NULL);
}
@@ -1166,6 +1171,15 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
*/
if(part_of_name == "[forcesingle")
{
// If base image is NULL, create a random color
if(baseimg == NULL)
{
core::dimension2d<u32> dim(1,1);
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
assert(baseimg);
baseimg->setPixel(0,0, video::SColor(255,myrand()%256,
myrand()%256,myrand()%256));
}
}
/*
[crackN
@@ -1455,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();
@@ -1486,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));
@@ -1506,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));
@@ -1527,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

@@ -23,9 +23,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <sstream>
#include "utility.h"
ToolDiggingProperties::ToolDiggingProperties(
ToolDiggingProperties::ToolDiggingProperties(float full_punch_interval_,
float a, float b, float c, float d, float e,
float f, float g, float h, float i, float j):
full_punch_interval(full_punch_interval_),
basetime(a),
dt_weight(b),
dt_crackiness(c),
@@ -60,6 +61,7 @@ void ToolDefinition::serialize(std::ostream &os)
writeF1000(os, properties.dd_crackiness);
writeF1000(os, properties.dd_crumbliness);
writeF1000(os, properties.dd_cuttability);
writeF1000(os, properties.full_punch_interval);
}
void ToolDefinition::deSerialize(std::istream &is)
@@ -78,6 +80,9 @@ void ToolDefinition::deSerialize(std::istream &is)
properties.dd_crackiness = readF1000(is);
properties.dd_crumbliness = readF1000(is);
properties.dd_cuttability = readF1000(is);
try{
properties.full_punch_interval = readF1000(is);
}catch(SerializationError &e){} // Temporary for 0.4.dev
}
class CToolDefManager: public IWritableToolDefManager

View File

@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
struct ToolDiggingProperties
{
// time = basetime + sum(feature here * feature in MaterialProperties)
float full_punch_interval;
float basetime;
float dt_weight;
float dt_crackiness;
@@ -37,7 +38,7 @@ struct ToolDiggingProperties
float dd_crumbliness;
float dd_cuttability;
ToolDiggingProperties(
ToolDiggingProperties(float full_punch_interval_=1.0,
float a=0.75, float b=0, float c=0, float d=0, float e=0,
float f=50, float g=0, float h=0, float i=0, float j=0);
};

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

View File

@@ -427,6 +427,10 @@ do
}
end
-- TOSERVER_RESPAWN
minetest_client_commands[0x38] = { "RESPAWN", 2 }
@@ -936,6 +940,40 @@ do
}
end
-- TOCLIENT_DEATHSCREEN
do
local vs_set_camera_point_target = {
[0] = "False",
[1] = "True"
}
local f_set_camera_point_target = ProtoField.uint8(
"minetest.server.deathscreen_set_camera_point_target",
"Set camera point target", base.DEC, vs_set_camera_point_target)
local f_camera_point_target_x = ProtoField.int32(
"minetest.server.deathscreen_camera_point_target_x",
"Camera point target X", base.DEC)
local f_camera_point_target_y = ProtoField.int32(
"minetest.server.deathscreen_camera_point_target_y",
"Camera point target Y", base.DEC)
local f_camera_point_target_z = ProtoField.int32(
"minetest.server.deathscreen_camera_point_target_z",
"Camera point target Z", base.DEC)
minetest_server_commands[0x37] = {
"DEATHSCREEN", 15,
{ f_set_camera_point_target, f_camera_point_target_x,
f_camera_point_target_y, f_camera_point_target_z},
function(buffer, pinfo, tree, t)
t:add(f_set_camera_point_target, buffer(2,1))
t:add(f_camera_point_target_x, buffer(3,4))
t:add(f_camera_point_target_y, buffer(7,4))
t:add(f_camera_point_target_z, buffer(11,4))
end
}
end
@@ -1280,6 +1318,12 @@ function minetest_convert_utf16(tvb, name)
hex = hex .. " 3F"
end
end
return ByteArray.new(hex):tvb(name):range()
if hex == "" then
-- This is a hack to avoid a failed assertion in tvbuff.c
-- (function: ensure_contiguous_no_exception)
return ByteArray.new("00"):tvb(name):range(0,0)
else
return ByteArray.new(hex):tvb(name):range()
end
end