Compare commits
58 Commits
0.4.dev-20
...
0.4.dev-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
569156b013 | ||
|
|
6d4bc012f0 | ||
|
|
2f5c28aaf1 | ||
|
|
4f2c1e36a1 | ||
|
|
bc743ca7ce | ||
|
|
f9d7e399b2 | ||
|
|
3e6f824e6c | ||
|
|
6286c555d4 | ||
|
|
4630281318 | ||
|
|
cd0019acd2 | ||
|
|
e82a76e438 | ||
|
|
ab57fbe4ca | ||
|
|
56f55ab1af | ||
|
|
2445cbbbdc | ||
|
|
48131bf988 | ||
|
|
2b9596fe9b | ||
|
|
0e1f448b61 | ||
|
|
ff82b95800 | ||
|
|
49b7055cb3 | ||
|
|
cb88f7b6d4 | ||
|
|
9425fb8192 | ||
|
|
e48ccd7943 | ||
|
|
6be5441176 | ||
|
|
d5ba7ebaf0 | ||
|
|
270a482740 | ||
|
|
e0b4890794 | ||
|
|
247e8b6e5d | ||
|
|
b760e2ba23 | ||
|
|
103173fc9b | ||
|
|
70ed371d0c | ||
|
|
81d3485109 | ||
|
|
7b7b68cdab | ||
|
|
135a65e200 | ||
|
|
123529e5eb | ||
|
|
e81989a0d8 | ||
|
|
1c15f53318 | ||
|
|
7937813c98 | ||
|
|
ad4040d982 | ||
|
|
69579306dd | ||
|
|
bd21f00f0a | ||
|
|
012bcbcb48 | ||
|
|
e06d4555bf | ||
|
|
abd106bacb | ||
|
|
008de2fb8f | ||
|
|
2e67fa3e48 | ||
|
|
ea36951bc4 | ||
|
|
09c48b60bd | ||
|
|
4cc117ddf6 | ||
|
|
ceaf8edade | ||
|
|
520200d597 | ||
|
|
ab67985d21 | ||
|
|
bc5cc638fc | ||
|
|
bff8be8b76 | ||
|
|
3e95b8a158 | ||
|
|
e8539d4dae | ||
|
|
1907b31da7 | ||
|
|
6145a135bd | ||
|
|
97c3bc408b |
@@ -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-20111204-1)
|
||||
set(VERSION_PATCH dev-20120106-1)
|
||||
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
||||
|
||||
MESSAGE(STATUS "*** Will build version ${VERSION_STRING} ***")
|
||||
|
||||
@@ -97,7 +97,6 @@ minetest.register_nodedef_defaults({
|
||||
post_effect_color = {a=0, r=0, g=0, b=0},
|
||||
paramtype = "none",
|
||||
is_ground_content = false,
|
||||
light_propagates = false,
|
||||
sunlight_propagates = false,
|
||||
walkable = true,
|
||||
pointable = true,
|
||||
@@ -133,7 +132,6 @@ minetest.register_nodedef_defaults({
|
||||
minetest.register_node("air", {
|
||||
drawtype = "airlike",
|
||||
paramtype = "light",
|
||||
light_propagates = true,
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
pointable = false,
|
||||
@@ -145,7 +143,6 @@ minetest.register_node("air", {
|
||||
minetest.register_node("ignore", {
|
||||
drawtype = "airlike",
|
||||
paramtype = "none",
|
||||
light_propagates = false,
|
||||
sunlight_propagates = false,
|
||||
walkable = false,
|
||||
pointable = false,
|
||||
@@ -304,7 +301,7 @@ end
|
||||
test_stackstring()
|
||||
|
||||
--
|
||||
-- nodeitem helpers
|
||||
-- NodeItem helpers
|
||||
--
|
||||
|
||||
minetest.inventorycube = function(img1, img2, img3)
|
||||
@@ -317,7 +314,7 @@ minetest.inventorycube = function(img1, img2, img3)
|
||||
end
|
||||
|
||||
--
|
||||
-- craftitem helpers
|
||||
-- CraftItem helpers
|
||||
--
|
||||
|
||||
minetest.craftitem_place_item = function(item, placer, pos)
|
||||
@@ -438,6 +435,7 @@ minetest.registered_on_dignodes, minetest.register_on_dignode = make_registratio
|
||||
minetest.registered_on_punchnodes, minetest.register_on_punchnode = make_registration()
|
||||
minetest.registered_on_generateds, minetest.register_on_generated = make_registration()
|
||||
minetest.registered_on_newplayers, minetest.register_on_newplayer = make_registration()
|
||||
minetest.registered_on_dieplayers, minetest.register_on_dieplayer = make_registration()
|
||||
minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make_registration()
|
||||
|
||||
-- END
|
||||
|
||||
@@ -73,16 +73,16 @@
|
||||
-- {x=num, y=num, z=num}
|
||||
--
|
||||
-- stackstring/itemstring: A stack of items in serialized format.
|
||||
-- eg. 'node "dirt" 5'
|
||||
-- eg. 'node "default:dirt" 5'
|
||||
-- eg. 'tool "default:pick_wood" 21323'
|
||||
-- eg. 'craft "apple" 2'
|
||||
-- eg. 'craft "default:apple" 2'
|
||||
--
|
||||
-- item: A single item in Lua table format.
|
||||
-- eg. {type="node", name="dirt"}
|
||||
-- eg. {type="node", name="default:dirt"}
|
||||
-- ^ a single dirt node
|
||||
-- eg. {type="tool", name="default:pick_wood", wear=21323}
|
||||
-- ^ a wooden pick about 1/3 weared out
|
||||
-- eg. {type="craft", name="apple"}
|
||||
-- eg. {type="craft", name="default:apple"}
|
||||
-- ^ an apple.
|
||||
--
|
||||
-- Global functions:
|
||||
@@ -101,8 +101,10 @@
|
||||
-- minetest.register_on_punchnode(func(pos, node, puncher))
|
||||
-- minetest.register_on_generated(func(minp, maxp))
|
||||
-- minetest.register_on_newplayer(func(ObjectRef))
|
||||
-- minetest.register_on_dieplayer(func(ObjectRef))
|
||||
-- minetest.register_on_respawnplayer(func(ObjectRef))
|
||||
-- ^ return true in func to disable regular player placement
|
||||
-- ^ currently called _before_ repositioning of player occurs
|
||||
-- minetest.register_on_chat_message(func(name, message))
|
||||
-- minetest.add_to_creative_inventory(itemstring)
|
||||
-- minetest.setting_get(name) -> string or nil
|
||||
@@ -110,6 +112,10 @@
|
||||
-- minetest.chat_send_all(text)
|
||||
-- minetest.chat_send_player(name, text)
|
||||
-- minetest.get_player_privs(name) -> set of privs
|
||||
-- minetest.get_inventory(location) -> InvRef
|
||||
-- minetest.get_modpath(modname) -> eg. "/home/user/.minetest/usermods/modname"
|
||||
-- ^ location = eg. {type="player", name="celeron55"}
|
||||
-- {type="node", pos={x=, y=, z=}}
|
||||
--
|
||||
-- stackstring_take_item(stackstring) -> stackstring, item
|
||||
-- stackstring_put_item(stackstring, item) -> stackstring, success
|
||||
@@ -146,14 +152,17 @@
|
||||
-- ^ Returns {name="ignore", ...} for unloaded area
|
||||
-- - get_node_or_nil(pos)
|
||||
-- ^ Returns nil for unloaded area
|
||||
-- - add_luaentity(pos, name)
|
||||
-- - get_node_light(pos, timeofday) -> 0...15 or nil
|
||||
-- ^ timeofday: nil = current time, 0 = night, 0.5 = day
|
||||
-- - add_entity(pos, name): Returns ObjectRef or nil if failed
|
||||
-- - add_item(pos, itemstring)
|
||||
-- - add_rat(pos)
|
||||
-- - add_firefly(pos)
|
||||
-- - get_meta(pos) -- Get a NodeMetaRef at that position
|
||||
-- - get_player_by_name(name) -- Get an ObjectRef to a player
|
||||
-- - get_objects_inside_radius(pos, radius)
|
||||
--
|
||||
-- NodeMetaRef
|
||||
-- NodeMetaRef (this stuff is subject to change in a future version)
|
||||
-- - get_type()
|
||||
-- - allows_text_input()
|
||||
-- - set_text(text) -- eg. set the text of a sign
|
||||
@@ -161,6 +170,7 @@
|
||||
-- - get_owner()
|
||||
-- Generic node metadata specific:
|
||||
-- - set_infotext(infotext)
|
||||
-- - get_inventory() -> InvRef
|
||||
-- - inventory_set_list(name, {item1, item2, ...})
|
||||
-- - inventory_get_list(name)
|
||||
-- - set_inventory_draw_spec(string)
|
||||
@@ -185,25 +195,53 @@
|
||||
-- ^ time_from_last_punch = time since last punch action of the puncher
|
||||
-- - right_click(clicker); clicker = an another ObjectRef
|
||||
-- - get_wield_digging_properties() -> digging property table
|
||||
-- - damage_wielded_item(num) (item damage/wear range is 0-65535)
|
||||
-- - add_to_inventory(itemstring): add an item to object inventory (actually only works for the player as of now)
|
||||
-- - add_to_inventory_later(itemstring): like above, but after callback returns (only allowed for craftitem callbacks)
|
||||
-- - get_hp(): returns number of hitpoints (2 * number of hearts)
|
||||
-- - set_hp(hp): set number of hitpoints (2 * number of hearts)
|
||||
-- LuaEntitySAO-only:
|
||||
-- LuaEntitySAO-only: (no-op for other objects)
|
||||
-- - setvelocity({x=num, y=num, z=num})
|
||||
-- - getvelocity() -> {x=num, y=num, z=num}
|
||||
-- - setacceleration({x=num, y=num, z=num})
|
||||
-- - getacceleration() -> {x=num, y=num, z=num}
|
||||
-- - setyaw(radians)
|
||||
-- - getyaw() -> radians
|
||||
-- - settexturemod(mod)
|
||||
-- - setsprite(p={x=0,y=0}, num_frames=1, framelength=0.2,
|
||||
-- - select_horiz_by_yawpitch=false)
|
||||
-- Player-only:
|
||||
-- - ^ Select sprite from spritesheet with optional animation and DM-style
|
||||
-- - texture selection based on yaw relative to camera
|
||||
-- - get_entity_name() (DEPRECATED: Will be removed in a future version)
|
||||
-- - get_luaentity()
|
||||
-- Player-only: (no-op for other objects)
|
||||
-- - get_player_name(): will return nil if is not a player
|
||||
-- - get_inventory() -> InvRef
|
||||
-- - inventory_set_list(name, {item1, item2, ...})
|
||||
-- - inventory_get_list(name) -> {item1, item2, ...}
|
||||
-- - damage_wielded_item(num) (item damage/wear range is 0-65535)
|
||||
-- - add_to_inventory(itemstring): add an item to object inventory
|
||||
-- - get_look_dir(): get camera direction as a unit vector
|
||||
-- - get_look_pitch(): pitch in radians
|
||||
-- - get_look_yaw(): yaw in radians (wraps around pretty randomly as of now)
|
||||
--
|
||||
-- InvRef methods:
|
||||
-- - get_size(listname): get size of a list
|
||||
-- - set_size(listname, size): set size of a list
|
||||
-- - get_stack(listname, i): get a copy of stack index i in list
|
||||
-- - set_stack(listname, i, stack): copy stack to index i in list
|
||||
-- - get_list(listname): return full list
|
||||
-- - set_list(listname, list): set full list (size will not change)
|
||||
-- - autoinsert_stack(listname, stack): insert stack somewhere in list
|
||||
-- - autoinsert_stackstring(listname, stackstring)
|
||||
--
|
||||
-- ItemStack methods:
|
||||
-- - peek_item(): return item from stack without removing it
|
||||
-- - take_item(): remove item from stack and return it
|
||||
-- - put_item(item): put item in stack; return false if not possible
|
||||
-- - put_stackstring(stackstring): return false if not possible
|
||||
--
|
||||
-- Registered entities:
|
||||
-- - Functions receive a "luaentity" as self:
|
||||
-- - It has the member .name, which is the registered name ("mod:thing")
|
||||
-- - It has the member .object, which is an ObjectRef pointing to the object
|
||||
-- - The original prototype stuff is visible directly via a metatable
|
||||
-- - Callbacks:
|
||||
@@ -219,8 +257,11 @@
|
||||
-- {
|
||||
-- physical = true,
|
||||
-- collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
|
||||
-- visual = "cube",
|
||||
-- visual = "cube"/"sprite",
|
||||
-- visual_size = {x=1, y=1},
|
||||
-- textures = {texture,texture,texture,texture,texture,texture},
|
||||
-- spritediv = {x=1, y=1},
|
||||
-- initial_sprite_basepos = {x=0, y=0},
|
||||
-- on_activate = function(self, staticdata),
|
||||
-- on_step = function(self, dtime),
|
||||
-- on_punch = function(self, hitter),
|
||||
@@ -261,7 +302,6 @@
|
||||
-- post_effect_color = {a=0, r=0, g=0, b=0},
|
||||
-- paramtype = "none",
|
||||
-- is_ground_content = false,
|
||||
-- light_propagates = false,
|
||||
-- sunlight_propagates = false,
|
||||
-- walkable = true,
|
||||
-- pointable = true,
|
||||
@@ -313,7 +353,7 @@
|
||||
-- {
|
||||
-- output = 'tool "default:pick_stone"',
|
||||
-- recipe = {
|
||||
-- {'node "cobble"', 'node "cobble"', 'node "cobble"'},
|
||||
-- {'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'},
|
||||
-- {'', 'craft "default:stick"', ''},
|
||||
-- {'', 'craft "default:stick"', ''},
|
||||
-- }
|
||||
@@ -321,8 +361,8 @@
|
||||
--
|
||||
-- ABM (ActiveBlockModifier) definition:
|
||||
-- {
|
||||
-- nodenames = {"lava_source"},
|
||||
-- neighbors = {"water_source", "water_flowing"}, -- (any of these)
|
||||
-- nodenames = {"default:lava_source"},
|
||||
-- neighbors = {"default:water_source", "default:water_flowing"}, -- (any of these)
|
||||
-- ^ If left out or empty, any neighbor will do
|
||||
-- ^ This might get removed in the future
|
||||
-- interval = 1.0, -- (operation interval)
|
||||
@@ -534,7 +574,7 @@ minetest.register_tool("default:sword_steel", {
|
||||
minetest.register_craft({
|
||||
output = 'node "default:wood" 4',
|
||||
recipe = {
|
||||
{'node "tree"'},
|
||||
{'node "default:tree"'},
|
||||
}
|
||||
})
|
||||
|
||||
@@ -546,7 +586,7 @@ minetest.register_craft({
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'node "fence_wooden" 2',
|
||||
output = 'node "default:fence_wood" 2',
|
||||
recipe = {
|
||||
{'craft "default:stick"', 'craft "default:stick"', 'craft "default:stick"'},
|
||||
{'craft "default:stick"', 'craft "default:stick"', 'craft "default:stick"'},
|
||||
@@ -582,7 +622,7 @@ minetest.register_craft({
|
||||
minetest.register_craft({
|
||||
output = 'tool "default:pick_stone"',
|
||||
recipe = {
|
||||
{'node "cobble"', 'node "cobble"', 'node "cobble"'},
|
||||
{'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'},
|
||||
{'', 'craft "default:stick"', ''},
|
||||
{'', 'craft "default:stick"', ''},
|
||||
}
|
||||
@@ -600,7 +640,7 @@ minetest.register_craft({
|
||||
minetest.register_craft({
|
||||
output = 'tool "default:pick_mese"',
|
||||
recipe = {
|
||||
{'node "mese"', 'node "mese"', 'node "mese"'},
|
||||
{'node "default:mese"', 'node "default:mese"', 'node "default:mese"'},
|
||||
{'', 'craft "default:stick"', ''},
|
||||
{'', 'craft "default:stick"', ''},
|
||||
}
|
||||
@@ -618,7 +658,7 @@ minetest.register_craft({
|
||||
minetest.register_craft({
|
||||
output = 'tool "default:shovel_stone"',
|
||||
recipe = {
|
||||
{'node "cobble"'},
|
||||
{'node "default:cobble"'},
|
||||
{'craft "default:stick"'},
|
||||
{'craft "default:stick"'},
|
||||
}
|
||||
@@ -645,8 +685,8 @@ minetest.register_craft({
|
||||
minetest.register_craft({
|
||||
output = 'tool "default:axe_stone"',
|
||||
recipe = {
|
||||
{'node "cobble"', 'node "cobble"'},
|
||||
{'node "cobble"', 'craft "default:stick"'},
|
||||
{'node "default:cobble"', 'node "default:cobble"'},
|
||||
{'node "default:cobble"', 'craft "default:stick"'},
|
||||
{'', 'craft "default:stick"'},
|
||||
}
|
||||
})
|
||||
@@ -672,8 +712,8 @@ minetest.register_craft({
|
||||
minetest.register_craft({
|
||||
output = 'tool "default:sword_stone"',
|
||||
recipe = {
|
||||
{'node "cobble"'},
|
||||
{'node "cobble"'},
|
||||
{'node "default:cobble"'},
|
||||
{'node "default:cobble"'},
|
||||
{'craft "default:stick"'},
|
||||
}
|
||||
})
|
||||
@@ -717,9 +757,9 @@ minetest.register_craft({
|
||||
minetest.register_craft({
|
||||
output = 'node "default:furnace" 1',
|
||||
recipe = {
|
||||
{'node "cobble"', 'node "cobble"', 'node "cobble"'},
|
||||
{'node "cobble"', '', 'node "cobble"'},
|
||||
{'node "cobble"', 'node "cobble"', 'node "cobble"'},
|
||||
{'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'},
|
||||
{'node "default:cobble"', '', 'node "default:cobble"'},
|
||||
{'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'},
|
||||
}
|
||||
})
|
||||
|
||||
@@ -735,8 +775,8 @@ minetest.register_craft({
|
||||
minetest.register_craft({
|
||||
output = 'node "default:sandstone" 1',
|
||||
recipe = {
|
||||
{'node "sand"', 'node "sand"'},
|
||||
{'node "sand"', 'node "sand"'},
|
||||
{'node "default:sand"', 'node "default:sand"'},
|
||||
{'node "default:sand"', 'node "default:sand"'},
|
||||
}
|
||||
})
|
||||
|
||||
@@ -759,7 +799,7 @@ minetest.register_craft({
|
||||
minetest.register_craft({
|
||||
output = 'craft "default:paper" 1',
|
||||
recipe = {
|
||||
{'node "papyrus"', 'node "papyrus"', 'node "papyrus"'},
|
||||
{'node "default:papyrus"', 'node "default:papyrus"', 'node "default:papyrus"'},
|
||||
}
|
||||
})
|
||||
|
||||
@@ -801,7 +841,7 @@ minetest.register_node("default:stone", {
|
||||
is_ground_content = true,
|
||||
often_contains_mineral = true, -- Texture atlas hint
|
||||
material = minetest.digprop_stonelike(1.0),
|
||||
dug_item = 'node "cobble" 1',
|
||||
dug_item = 'node "default:cobble" 1',
|
||||
})
|
||||
|
||||
minetest.register_node("default:dirt_with_grass", {
|
||||
@@ -809,7 +849,7 @@ minetest.register_node("default:dirt_with_grass", {
|
||||
inventory_image = minetest.inventorycube("default_dirt.png^default_grass_side.png"),
|
||||
is_ground_content = true,
|
||||
material = minetest.digprop_dirtlike(1.0),
|
||||
dug_item = 'node "dirt" 1',
|
||||
dug_item = 'node "default:dirt" 1',
|
||||
})
|
||||
|
||||
minetest.register_node("default:dirt_with_grass_footsteps", {
|
||||
@@ -817,7 +857,7 @@ minetest.register_node("default:dirt_with_grass_footsteps", {
|
||||
inventory_image = "default_grass_footsteps.png",
|
||||
is_ground_content = true,
|
||||
material = minetest.digprop_dirtlike(1.0),
|
||||
dug_item = 'node "dirt" 1',
|
||||
dug_item = 'node "default:dirt" 1',
|
||||
})
|
||||
|
||||
minetest.register_node("default:dirt", {
|
||||
@@ -832,7 +872,7 @@ minetest.register_node("default:sand", {
|
||||
inventory_image = minetest.inventorycube("default_sand.png"),
|
||||
is_ground_content = true,
|
||||
material = minetest.digprop_dirtlike(1.0),
|
||||
cookresult_itemstring = 'node "glass" 1',
|
||||
cookresult_itemstring = 'node "default:glass" 1',
|
||||
})
|
||||
|
||||
minetest.register_node("default:gravel", {
|
||||
@@ -847,7 +887,7 @@ minetest.register_node("default:sandstone", {
|
||||
inventory_image = minetest.inventorycube("default_sandstone.png"),
|
||||
is_ground_content = true,
|
||||
material = minetest.digprop_dirtlike(1.0), -- FIXME should this be stonelike?
|
||||
dug_item = 'node "sand" 1', -- FIXME is this intentional?
|
||||
dug_item = 'node "default:sand" 1', -- FIXME is this intentional?
|
||||
})
|
||||
|
||||
minetest.register_node("default:clay", {
|
||||
@@ -889,7 +929,6 @@ minetest.register_node("default:junglegrass", {
|
||||
visual_scale = 1.3,
|
||||
tile_images = {"default_junglegrass.png"},
|
||||
inventory_image = "default_junglegrass.png",
|
||||
light_propagates = true,
|
||||
paramtype = "light",
|
||||
walkable = false,
|
||||
material = minetest.digprop_leaveslike(1.0),
|
||||
@@ -901,10 +940,9 @@ minetest.register_node("default:leaves", {
|
||||
visual_scale = 1.3,
|
||||
tile_images = {"default_leaves.png"},
|
||||
inventory_image = minetest.inventorycube("default_leaves.png"),
|
||||
light_propagates = true,
|
||||
paramtype = "light",
|
||||
material = minetest.digprop_leaveslike(1.0),
|
||||
extra_dug_item = 'node "sapling" 1',
|
||||
extra_dug_item = 'node "default:sapling" 1',
|
||||
extra_dug_item_rarity = 20,
|
||||
furnace_burntime = 1,
|
||||
})
|
||||
@@ -921,7 +959,6 @@ minetest.register_node("default:papyrus", {
|
||||
drawtype = "plantlike",
|
||||
tile_images = {"default_papyrus.png"},
|
||||
inventory_image = "default_papyrus.png",
|
||||
light_propagates = true,
|
||||
paramtype = "light",
|
||||
is_ground_content = true,
|
||||
walkable = false,
|
||||
@@ -941,18 +978,16 @@ minetest.register_node("default:glass", {
|
||||
drawtype = "glasslike",
|
||||
tile_images = {"default_glass.png"},
|
||||
inventory_image = minetest.inventorycube("default_glass.png"),
|
||||
light_propagates = true,
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = true,
|
||||
material = minetest.digprop_glasslike(1.0),
|
||||
})
|
||||
|
||||
minetest.register_node("default:fence_wooden", {
|
||||
minetest.register_node("default:fence_wood", {
|
||||
drawtype = "fencelike",
|
||||
tile_images = {"default_wood.png"},
|
||||
inventory_image = "default_fence.png",
|
||||
light_propagates = true,
|
||||
paramtype = "light",
|
||||
is_ground_content = true,
|
||||
selection_box = {
|
||||
@@ -967,7 +1002,6 @@ minetest.register_node("default:rail", {
|
||||
drawtype = "raillike",
|
||||
tile_images = {"default_rail.png", "default_rail_curved.png", "default_rail_t_junction.png", "default_rail_crossing.png"},
|
||||
inventory_image = "default_rail.png",
|
||||
light_propagates = true,
|
||||
paramtype = "light",
|
||||
is_ground_content = true,
|
||||
walkable = false,
|
||||
@@ -982,7 +1016,6 @@ minetest.register_node("default:ladder", {
|
||||
drawtype = "signlike",
|
||||
tile_images = {"default_ladder.png"},
|
||||
inventory_image = "default_ladder.png",
|
||||
light_propagates = true,
|
||||
paramtype = "light",
|
||||
is_ground_content = true,
|
||||
wall_mounted = true,
|
||||
@@ -1026,14 +1059,13 @@ minetest.register_node("default:water_flowing", {
|
||||
alpha = WATER_ALPHA,
|
||||
inventory_image = minetest.inventorycube("default_water.png"),
|
||||
paramtype = "light",
|
||||
light_propagates = true,
|
||||
walkable = false,
|
||||
pointable = false,
|
||||
diggable = false,
|
||||
buildable_to = true,
|
||||
liquidtype = "flowing",
|
||||
liquid_alternative_flowing = "water_flowing",
|
||||
liquid_alternative_source = "water_source",
|
||||
liquid_alternative_flowing = "default:water_flowing",
|
||||
liquid_alternative_source = "default:water_source",
|
||||
liquid_viscosity = WATER_VISC,
|
||||
post_effect_color = {a=64, r=100, g=100, b=200},
|
||||
special_materials = {
|
||||
@@ -1048,14 +1080,13 @@ minetest.register_node("default:water_source", {
|
||||
alpha = WATER_ALPHA,
|
||||
inventory_image = minetest.inventorycube("default_water.png"),
|
||||
paramtype = "light",
|
||||
light_propagates = true,
|
||||
walkable = false,
|
||||
pointable = false,
|
||||
diggable = false,
|
||||
buildable_to = true,
|
||||
liquidtype = "source",
|
||||
liquid_alternative_flowing = "water_flowing",
|
||||
liquid_alternative_source = "water_source",
|
||||
liquid_alternative_flowing = "default:water_flowing",
|
||||
liquid_alternative_source = "default:water_source",
|
||||
liquid_viscosity = WATER_VISC,
|
||||
post_effect_color = {a=64, r=100, g=100, b=200},
|
||||
special_materials = {
|
||||
@@ -1069,15 +1100,14 @@ minetest.register_node("default:lava_flowing", {
|
||||
tile_images = {"default_lava.png"},
|
||||
inventory_image = minetest.inventorycube("default_lava.png"),
|
||||
paramtype = "light",
|
||||
light_propagates = false,
|
||||
light_source = LIGHT_MAX - 1,
|
||||
walkable = false,
|
||||
pointable = false,
|
||||
diggable = false,
|
||||
buildable_to = true,
|
||||
liquidtype = "flowing",
|
||||
liquid_alternative_flowing = "lava_flowing",
|
||||
liquid_alternative_source = "lava_source",
|
||||
liquid_alternative_flowing = "default:lava_flowing",
|
||||
liquid_alternative_source = "default:lava_source",
|
||||
liquid_viscosity = LAVA_VISC,
|
||||
damage_per_second = 4*2,
|
||||
post_effect_color = {a=192, r=255, g=64, b=0},
|
||||
@@ -1092,15 +1122,14 @@ minetest.register_node("default:lava_source", {
|
||||
tile_images = {"default_lava.png"},
|
||||
inventory_image = minetest.inventorycube("default_lava.png"),
|
||||
paramtype = "light",
|
||||
light_propagates = false,
|
||||
light_source = LIGHT_MAX - 1,
|
||||
walkable = false,
|
||||
pointable = false,
|
||||
diggable = false,
|
||||
buildable_to = true,
|
||||
liquidtype = "source",
|
||||
liquid_alternative_flowing = "lava_flowing",
|
||||
liquid_alternative_source = "lava_source",
|
||||
liquid_alternative_flowing = "default:lava_flowing",
|
||||
liquid_alternative_source = "default:lava_source",
|
||||
liquid_viscosity = LAVA_VISC,
|
||||
damage_per_second = 4*2,
|
||||
post_effect_color = {a=192, r=255, g=64, b=0},
|
||||
@@ -1116,7 +1145,6 @@ minetest.register_node("default:torch", {
|
||||
tile_images = {"default_torch_on_floor.png", "default_torch_on_ceiling.png", "default_torch.png"},
|
||||
inventory_image = "default_torch_on_floor.png",
|
||||
paramtype = "light",
|
||||
light_propagates = true,
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
wall_mounted = true,
|
||||
@@ -1136,7 +1164,6 @@ minetest.register_node("default:sign_wall", {
|
||||
tile_images = {"default_sign_wall.png"},
|
||||
inventory_image = "default_sign_wall.png",
|
||||
paramtype = "light",
|
||||
light_propagates = true,
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
wall_mounted = true,
|
||||
@@ -1184,7 +1211,7 @@ minetest.register_node("default:cobble", {
|
||||
tile_images = {"default_cobble.png"},
|
||||
inventory_image = minetest.inventorycube("default_cobble.png"),
|
||||
is_ground_content = true,
|
||||
cookresult_itemstring = 'node "stone" 1',
|
||||
cookresult_itemstring = 'node "default:stone" 1',
|
||||
material = minetest.digprop_stonelike(0.9),
|
||||
})
|
||||
|
||||
@@ -1224,7 +1251,6 @@ minetest.register_node("default:sapling", {
|
||||
tile_images = {"default_sapling.png"},
|
||||
inventory_image = "default_sapling.png",
|
||||
paramtype = "light",
|
||||
light_propagates = true,
|
||||
walkable = false,
|
||||
material = minetest.digprop_constanttime(0.0),
|
||||
furnace_burntime = 10,
|
||||
@@ -1236,10 +1262,9 @@ minetest.register_node("default:apple", {
|
||||
tile_images = {"default_apple.png"},
|
||||
inventory_image = "default_apple.png",
|
||||
paramtype = "light",
|
||||
light_propagates = true,
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
dug_item = 'craft "apple" 1',
|
||||
dug_item = 'craft "default:apple" 1',
|
||||
material = minetest.digprop_constanttime(0.0),
|
||||
furnace_burntime = 3,
|
||||
})
|
||||
@@ -1321,6 +1346,7 @@ minetest.add_to_creative_inventory('node "default:sandstone" 0')
|
||||
minetest.add_to_creative_inventory('node "default:clay" 0')
|
||||
minetest.add_to_creative_inventory('node "default:brick" 0')
|
||||
minetest.add_to_creative_inventory('node "default:tree" 0')
|
||||
minetest.add_to_creative_inventory('node "default:wood" 0')
|
||||
minetest.add_to_creative_inventory('node "default:leaves" 0')
|
||||
minetest.add_to_creative_inventory('node "default:cactus" 0')
|
||||
minetest.add_to_creative_inventory('node "default:papyrus" 0')
|
||||
@@ -1349,7 +1375,7 @@ function nodeupdate_single(p)
|
||||
n_bottom = minetest.env:get_node(p_bottom)
|
||||
if n_bottom.name == "air" then
|
||||
minetest.env:remove_node(p)
|
||||
minetest.env:add_luaentity(p, "default:falling_"..n.name)
|
||||
minetest.env:add_entity(p, "default:falling_"..n.name)
|
||||
nodeupdate(p)
|
||||
end
|
||||
end
|
||||
@@ -1488,6 +1514,30 @@ minetest.register_on_chat_message(function(name, message)
|
||||
end
|
||||
return true -- Handled chat message
|
||||
end
|
||||
local cmd = "/spawnentity"
|
||||
if message:sub(0, #cmd) == cmd then
|
||||
if not minetest.get_player_privs(name)["give"] then
|
||||
minetest.chat_send_player(name, "you don't have permission to spawn (give)")
|
||||
return true -- Handled chat message
|
||||
end
|
||||
local entityname = string.match(message, cmd.." (.*)")
|
||||
if entityname == nil then
|
||||
minetest.chat_send_player(name, 'usage: '..cmd..' entityname')
|
||||
return true -- Handled chat message
|
||||
end
|
||||
print(cmd..' invoked, entityname="'..entityname..'"')
|
||||
local player = minetest.env:get_player_by_name(name)
|
||||
if player == nil then
|
||||
print("Unable to spawn entity, player is nil")
|
||||
return true -- Handled chat message
|
||||
end
|
||||
local p = player:getpos()
|
||||
p.y = p.y + 1
|
||||
minetest.env:add_entity(p, entityname)
|
||||
minetest.chat_send_player(name, '"'..entityname
|
||||
..'" spawned.');
|
||||
return true -- Handled chat message
|
||||
end
|
||||
end)
|
||||
|
||||
--
|
||||
|
||||
@@ -2,6 +2,27 @@
|
||||
-- Experimental things
|
||||
--
|
||||
|
||||
-- For testing random stuff
|
||||
|
||||
function on_step(dtime)
|
||||
-- print("experimental on_step")
|
||||
--[[
|
||||
objs = minetest.env:get_objects_inside_radius({x=0,y=0,z=0}, 10)
|
||||
for k, obj in pairs(objs) do
|
||||
name = obj:get_player_name()
|
||||
if name then
|
||||
print(name.." at "..dump(obj:getpos()))
|
||||
print(name.." dir: "..dump(obj:get_look_dir()))
|
||||
print(name.." pitch: "..dump(obj:get_look_pitch()))
|
||||
print(name.." yaw: "..dump(obj:get_look_yaw()))
|
||||
else
|
||||
print("Some object at "..dump(obj:getpos()))
|
||||
end
|
||||
end
|
||||
--]]
|
||||
end
|
||||
minetest.register_globalstep(on_step)
|
||||
|
||||
-- An example furnace-thing implemented in Lua
|
||||
|
||||
minetest.register_node("experimental:luafurnace", {
|
||||
@@ -35,6 +56,127 @@ minetest.register_on_placenode(function(pos, newnode, placer)
|
||||
end
|
||||
end)
|
||||
|
||||
local get_item_definition = function(item)
|
||||
if not item then return nil end
|
||||
if item.type == "node" then
|
||||
return minetest.registered_nodes[item.name]
|
||||
elseif item.type == "craft" then
|
||||
return minetest.registered_craftitems[item.name]
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"experimental:luafurnace"},
|
||||
interval = 1.0,
|
||||
chance = 1,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
local meta = minetest.env:get_meta(pos)
|
||||
for i, name in ipairs({
|
||||
"fuel_totaltime",
|
||||
"fuel_time",
|
||||
"src_totaltime",
|
||||
"src_time"
|
||||
}) do
|
||||
if not meta:get_string(name) then
|
||||
meta:set_string(name, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
local fuelitem = inv:get_stack("fuel", 1):peek_item()
|
||||
local srcitem = inv:get_stack("src", 1):peek_item()
|
||||
--print("fuelitem="..dump(fuelitem))
|
||||
--print("srcitem="..dump(srcitem))
|
||||
|
||||
local was_active = false
|
||||
|
||||
local src_cooktime = -1
|
||||
local result_stackstring = nil
|
||||
|
||||
if srcitem then
|
||||
local prop = get_item_definition(srcitem)
|
||||
if prop and prop.cookresult_itemstring ~= "" then
|
||||
result_stackstring = prop.cookresult_itemstring
|
||||
src_cooktime = prop.furnace_cooktime or 3
|
||||
end
|
||||
end
|
||||
|
||||
print("src_cooktime="..dump(src_cooktime))
|
||||
print("result_stackstring="..dump(result_stackstring))
|
||||
|
||||
if tonumber(meta:get_string("fuel_time")) < tonumber(meta:get_string("fuel_totaltime")) then
|
||||
was_active = true
|
||||
meta:set_string("fuel_time", tonumber(meta:get_string("fuel_time")) + 1)
|
||||
meta:set_string("src_time", tonumber(meta:get_string("src_time")) + 1)
|
||||
--print("result_stackstring="..dump(result_stackstring))
|
||||
--print('tonumber(meta:get_string("src_time"))='..dump(tonumber(meta:get_string("src_time"))))
|
||||
--print("src_cooktime="..dump(src_cooktime))
|
||||
if result_stackstring and tonumber(meta:get_string("src_time")) >= src_cooktime and src_cooktime >= 0 then
|
||||
-- Put result in "dst" list
|
||||
success = inv:autoinsert_stackstring("dst", result_stackstring)
|
||||
if not success then
|
||||
print("Could not autoinsert '"..result_stackstring.."'")
|
||||
end
|
||||
-- If succeeded, take stuff from "src" list
|
||||
if success then
|
||||
srcstack = inv:get_stack("src", 1)
|
||||
srcstack:take_item()
|
||||
inv:set_stack("src", 1, srcstack)
|
||||
end
|
||||
meta:set_string("src_time", 0)
|
||||
end
|
||||
end
|
||||
|
||||
if tonumber(meta:get_string("fuel_time")) < tonumber(meta:get_string("fuel_totaltime")) then
|
||||
meta:set_infotext("Furnace active: "..(tonumber(meta:get_string("fuel_time"))/tonumber(meta:get_string("fuel_totaltime"))*100).."%")
|
||||
return
|
||||
end
|
||||
|
||||
local srcitem = inv:get_stack("src", 1):peek_item()
|
||||
|
||||
local src_cooktime = 0
|
||||
local result_stackstring = nil
|
||||
|
||||
if srcitem then
|
||||
local prop = get_item_definition(srcitem)
|
||||
if prop and prop.cookresult_itemstring ~= "" then
|
||||
result_stackstring = prop.cookresult_itemstring
|
||||
src_cooktime = prop.furnace_cooktime or 3
|
||||
end
|
||||
end
|
||||
|
||||
local fuelitem = inv:get_stack("fuel", 1):peek_item()
|
||||
|
||||
if not result_stackstring or not fuelitem then
|
||||
if was_active then
|
||||
meta:set_infotext("Furnace is empty")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local burntime = -1
|
||||
if fuelitem then
|
||||
local prop = get_item_definition(fuelitem)
|
||||
if prop then
|
||||
burntime = prop.furnace_burntime or -1
|
||||
end
|
||||
end
|
||||
|
||||
if burntime <= 0 then
|
||||
meta:set_infotext("Furnace out of fuel")
|
||||
return
|
||||
end
|
||||
|
||||
meta:set_string("fuel_totaltime", burntime)
|
||||
meta:set_string("fuel_time", 0)
|
||||
|
||||
local stack = inv:get_stack("fuel", 1)
|
||||
stack:take_item()
|
||||
inv:set_stack("fuel", 1, stack)
|
||||
end,
|
||||
})
|
||||
--[[
|
||||
minetest.register_abm({
|
||||
nodenames = {"experimental:luafurnace"},
|
||||
interval = 1.0,
|
||||
@@ -89,7 +231,7 @@ minetest.register_abm({
|
||||
meta:set_infotext("Lua Furnace: total cooked: "..total_cooked)
|
||||
end,
|
||||
})
|
||||
|
||||
--]]
|
||||
minetest.register_craft({
|
||||
output = 'node "experimental:luafurnace" 1',
|
||||
recipe = {
|
||||
@@ -169,7 +311,7 @@ minetest.register_node("experimental: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")
|
||||
minetest.env:add_entity(p, "experimental:tnt")
|
||||
nodeupdate(p)
|
||||
end
|
||||
end)
|
||||
@@ -237,6 +379,9 @@ end
|
||||
--print("Registering TNT");
|
||||
minetest.register_entity("experimental:tnt", TNT)
|
||||
|
||||
-- Add TNT's old name also
|
||||
minetest.alias_node("TNT", "experimental:tnt")
|
||||
|
||||
--
|
||||
-- A test entity for testing animated and yaw-modulated sprites
|
||||
--
|
||||
@@ -402,4 +547,6 @@ minetest.register_abm({
|
||||
end,
|
||||
})--]]
|
||||
|
||||
print("experimental modpath="..dump(minetest.get_modpath("experimental")))
|
||||
|
||||
-- END
|
||||
|
||||
@@ -34,6 +34,7 @@ minetest.alias_node("lava_flowing", "default:lava_flowing")
|
||||
minetest.alias_node("lava_source", "default:lava_source")
|
||||
minetest.alias_node("torch", "default:torch")
|
||||
minetest.alias_node("sign_wall", "default:sign_wall")
|
||||
minetest.alias_node("furnace", "default:furnace")
|
||||
minetest.alias_node("chest", "default:chest")
|
||||
minetest.alias_node("locked_chest", "default:chest_locked")
|
||||
minetest.alias_node("cobble", "default:cobble")
|
||||
|
||||
|
Before Width: | Height: | Size: 603 B After Width: | Height: | Size: 603 B |
@@ -94,6 +94,7 @@ configure_file(
|
||||
)
|
||||
|
||||
set(common_SRCS
|
||||
inventorymanager.cpp
|
||||
mods.cpp
|
||||
serverremoteplayer.cpp
|
||||
content_abm.cpp
|
||||
@@ -158,7 +159,6 @@ endif()
|
||||
# Client sources
|
||||
set(minetest_SRCS
|
||||
${common_SRCS}
|
||||
MyBillboardSceneNode.cpp
|
||||
content_mapblock.cpp
|
||||
content_cao.cpp
|
||||
mesh.cpp
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
// Copyright (C) 2002-2010 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "MyBillboardSceneNode.h"
|
||||
#include "IVideoDriver.h"
|
||||
#include "ISceneManager.h"
|
||||
#include "ICameraSceneNode.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene
|
||||
{
|
||||
|
||||
//! constructor
|
||||
MyBillboardSceneNode::MyBillboardSceneNode(ISceneNode* parent,
|
||||
ISceneManager* mgr, s32 id,
|
||||
const core::vector3df& position, const core::dimension2d<f32>& size)
|
||||
: IBillboardSceneNode(parent, mgr, id, position)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("MyBillboardSceneNode");
|
||||
#endif
|
||||
|
||||
setSize(size);
|
||||
|
||||
indices[0] = 0;
|
||||
indices[1] = 2;
|
||||
indices[2] = 1;
|
||||
indices[3] = 0;
|
||||
indices[4] = 3;
|
||||
indices[5] = 2;
|
||||
|
||||
video::SColor colorTop = video::SColor(0xFFFFFFFF);
|
||||
video::SColor colorBottom = video::SColor(0xFFFFFFFF);
|
||||
|
||||
vertices[0].TCoords.set(1.0f, 1.0f);
|
||||
vertices[0].Color = colorBottom;
|
||||
|
||||
vertices[1].TCoords.set(1.0f, 0.0f);
|
||||
vertices[1].Color = colorTop;
|
||||
|
||||
vertices[2].TCoords.set(0.0f, 0.0f);
|
||||
vertices[2].Color = colorTop;
|
||||
|
||||
vertices[3].TCoords.set(0.0f, 1.0f);
|
||||
vertices[3].Color = colorBottom;
|
||||
}
|
||||
|
||||
|
||||
//! pre render event
|
||||
void MyBillboardSceneNode::OnRegisterSceneNode()
|
||||
{
|
||||
if (IsVisible)
|
||||
SceneManager->registerNodeForRendering(this);
|
||||
|
||||
ISceneNode::OnRegisterSceneNode();
|
||||
}
|
||||
|
||||
|
||||
//! render
|
||||
void MyBillboardSceneNode::render()
|
||||
{
|
||||
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
||||
ICameraSceneNode* camera = SceneManager->getActiveCamera();
|
||||
|
||||
if (!camera || !driver)
|
||||
return;
|
||||
|
||||
// make billboard look to camera
|
||||
|
||||
core::vector3df pos = getAbsolutePosition();
|
||||
|
||||
core::vector3df campos = camera->getAbsolutePosition();
|
||||
core::vector3df target = camera->getTarget();
|
||||
core::vector3df up = camera->getUpVector();
|
||||
core::vector3df view = target - campos;
|
||||
view.normalize();
|
||||
|
||||
core::vector3df horizontal = up.crossProduct(view);
|
||||
if ( horizontal.getLength() == 0 )
|
||||
{
|
||||
horizontal.set(up.Y,up.X,up.Z);
|
||||
}
|
||||
horizontal.normalize();
|
||||
horizontal *= 0.5f * Size.Width;
|
||||
|
||||
core::vector3df vertical = horizontal.crossProduct(view);
|
||||
vertical.normalize();
|
||||
vertical *= 0.5f * Size.Height;
|
||||
|
||||
view *= -1.0f;
|
||||
|
||||
for (s32 i=0; i<4; ++i)
|
||||
vertices[i].Normal = view;
|
||||
|
||||
vertices[0].Pos = pos + horizontal + vertical;
|
||||
vertices[1].Pos = pos + horizontal - vertical;
|
||||
vertices[2].Pos = pos - horizontal - vertical;
|
||||
vertices[3].Pos = pos - horizontal + vertical;
|
||||
|
||||
// draw
|
||||
|
||||
if ( DebugDataVisible & scene::EDS_BBOX )
|
||||
{
|
||||
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
||||
video::SMaterial m;
|
||||
m.Lighting = false;
|
||||
driver->setMaterial(m);
|
||||
driver->draw3DBox(BBox, video::SColor(0,208,195,152));
|
||||
}
|
||||
|
||||
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
|
||||
|
||||
driver->setMaterial(Material);
|
||||
|
||||
driver->drawIndexedTriangleList(vertices, 4, indices, 2);
|
||||
}
|
||||
|
||||
|
||||
//! returns the axis aligned bounding box of this node
|
||||
const core::aabbox3d<f32>& MyBillboardSceneNode::getBoundingBox() const
|
||||
{
|
||||
return BBox;
|
||||
}
|
||||
|
||||
|
||||
//! sets the size of the billboard
|
||||
void MyBillboardSceneNode::setSize(const core::dimension2d<f32>& size)
|
||||
{
|
||||
Size = size;
|
||||
|
||||
if (Size.Width == 0.0f)
|
||||
Size.Width = 1.0f;
|
||||
|
||||
if (Size.Height == 0.0f )
|
||||
Size.Height = 1.0f;
|
||||
|
||||
f32 avg = (size.Width + size.Height)/6;
|
||||
BBox.MinEdge.set(-avg,-avg,-avg);
|
||||
BBox.MaxEdge.set(avg,avg,avg);
|
||||
}
|
||||
|
||||
|
||||
video::SMaterial& MyBillboardSceneNode::getMaterial(u32 i)
|
||||
{
|
||||
return Material;
|
||||
}
|
||||
|
||||
|
||||
//! returns amount of materials used by this scene node.
|
||||
u32 MyBillboardSceneNode::getMaterialCount() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//! gets the size of the billboard
|
||||
const core::dimension2d<f32>& MyBillboardSceneNode::getSize() const
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
||||
//! Set the color of all vertices of the billboard
|
||||
//! \param overallColor: the color to set
|
||||
void MyBillboardSceneNode::setColor(const video::SColor & overallColor)
|
||||
{
|
||||
for(u32 vertex = 0; vertex < 4; ++vertex)
|
||||
vertices[vertex].Color = overallColor;
|
||||
}
|
||||
|
||||
|
||||
//! Set the color of the top and bottom vertices of the billboard
|
||||
//! \param topColor: the color to set the top vertices
|
||||
//! \param bottomColor: the color to set the bottom vertices
|
||||
void MyBillboardSceneNode::setColor(const video::SColor & topColor, const video::SColor & bottomColor)
|
||||
{
|
||||
vertices[0].Color = bottomColor;
|
||||
vertices[1].Color = topColor;
|
||||
vertices[2].Color = topColor;
|
||||
vertices[3].Color = bottomColor;
|
||||
}
|
||||
|
||||
|
||||
//! Gets the color of the top and bottom vertices of the billboard
|
||||
//! \param[out] topColor: stores the color of the top vertices
|
||||
//! \param[out] bottomColor: stores the color of the bottom vertices
|
||||
void MyBillboardSceneNode::getColor(video::SColor & topColor, video::SColor & bottomColor) const
|
||||
{
|
||||
bottomColor = vertices[0].Color;
|
||||
topColor = vertices[1].Color;
|
||||
}
|
||||
|
||||
void MyBillboardSceneNode::setTCoords(u32 i, core::vector2d<f32> c)
|
||||
{
|
||||
vertices[i].TCoords = c;
|
||||
}
|
||||
|
||||
} // end namespace scene
|
||||
} // end namespace irr
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright (C) 2002-2010 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __C_BILLBOARD_SCENE_NODE_H_INCLUDED__
|
||||
#define __C_BILLBOARD_SCENE_NODE_H_INCLUDED__
|
||||
|
||||
#include "IBillboardSceneNode.h"
|
||||
#include "S3DVertex.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene
|
||||
{
|
||||
|
||||
//! Scene node which is a billboard. A billboard is like a 3d sprite: A 2d element,
|
||||
//! which always looks to the camera.
|
||||
class MyBillboardSceneNode : virtual public IBillboardSceneNode
|
||||
{
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
MyBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
|
||||
const core::vector3df& position, const core::dimension2d<f32>& size);
|
||||
|
||||
//! pre render event
|
||||
virtual void OnRegisterSceneNode();
|
||||
|
||||
//! render
|
||||
virtual void render();
|
||||
|
||||
//! returns the axis aligned bounding box of this node
|
||||
virtual const core::aabbox3d<f32>& getBoundingBox() const;
|
||||
|
||||
//! sets the size of the billboard
|
||||
virtual void setSize(const core::dimension2d<f32>& size);
|
||||
|
||||
//! gets the size of the billboard
|
||||
virtual const core::dimension2d<f32>& getSize() const;
|
||||
|
||||
virtual video::SMaterial& getMaterial(u32 i);
|
||||
|
||||
//! returns amount of materials used by this scene node.
|
||||
virtual u32 getMaterialCount() const;
|
||||
|
||||
//! Set the color of all vertices of the billboard
|
||||
//! \param overallColor: the color to set
|
||||
virtual void setColor(const video::SColor & overallColor);
|
||||
|
||||
//! Set the color of the top and bottom vertices of the billboard
|
||||
//! \param topColor: the color to set the top vertices
|
||||
//! \param bottomColor: the color to set the bottom vertices
|
||||
virtual void setColor(const video::SColor & topColor, const video::SColor & bottomColor);
|
||||
|
||||
//! Gets the color of the top and bottom vertices of the billboard
|
||||
//! \param[out] topColor: stores the color of the top vertices
|
||||
//! \param[out] bottomColor: stores the color of the bottom vertices
|
||||
virtual void getColor(video::SColor& topColor, video::SColor& bottomColor) const;
|
||||
|
||||
virtual void setTCoords(u32 i, core::vector2d<f32> c);
|
||||
|
||||
private:
|
||||
|
||||
core::dimension2d<f32> Size;
|
||||
core::aabbox3d<f32> BBox;
|
||||
video::SMaterial Material;
|
||||
|
||||
video::S3DVertex vertices[4];
|
||||
u16 indices[6];
|
||||
};
|
||||
|
||||
|
||||
} // end namespace scene
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
||||
223
src/client.cpp
223
src/client.cpp
@@ -36,6 +36,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "tooldef.h"
|
||||
#include "craftitemdef.h"
|
||||
#include <IFileSystem.h>
|
||||
#include "sha1.h"
|
||||
#include "base64.h"
|
||||
|
||||
static std::string getTextureCacheDir()
|
||||
{
|
||||
return porting::path_userdata + DIR_DELIM + "cache" + DIR_DELIM + "texture";
|
||||
}
|
||||
|
||||
struct TextureRequest
|
||||
{
|
||||
std::string name;
|
||||
|
||||
TextureRequest(const std::string &name_=""):
|
||||
name(name_)
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
QueuedMeshUpdate
|
||||
@@ -1232,6 +1248,162 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
event.deathscreen.camera_point_target_z = camera_point_target.Z;
|
||||
m_client_event_queue.push_back(event);
|
||||
}
|
||||
else if(command == TOCLIENT_ANNOUNCE_TEXTURES)
|
||||
{
|
||||
io::IFileSystem *irrfs = m_device->getFileSystem();
|
||||
video::IVideoDriver *vdrv = m_device->getVideoDriver();
|
||||
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is(datastring, std::ios_base::binary);
|
||||
|
||||
|
||||
// Stop threads while updating content definitions
|
||||
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();
|
||||
}
|
||||
|
||||
int num_textures = readU16(is);
|
||||
|
||||
core::list<TextureRequest> texture_requests;
|
||||
|
||||
for(int i=0; i<num_textures; i++){
|
||||
|
||||
bool texture_found = false;
|
||||
|
||||
//read texture from cache
|
||||
std::string name = deSerializeString(is);
|
||||
std::string sha1_texture = deSerializeString(is);
|
||||
|
||||
// if name contains illegal characters, ignore the texture
|
||||
if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
|
||||
errorstream<<"Client: ignoring illegal texture name "
|
||||
<<"sent by server: \""<<name<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string tpath = getTextureCacheDir() + DIR_DELIM + name;
|
||||
// Read data
|
||||
std::ifstream fis(tpath.c_str(), std::ios_base::binary);
|
||||
|
||||
|
||||
if(fis.good() == false){
|
||||
infostream<<"Client::Texture not found in cache: "
|
||||
<<name << " expected it at: "<<tpath<<std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream tmp_os(std::ios_base::binary);
|
||||
bool bad = false;
|
||||
for(;;){
|
||||
char buf[1024];
|
||||
fis.read(buf, 1024);
|
||||
std::streamsize len = fis.gcount();
|
||||
tmp_os.write(buf, len);
|
||||
if(fis.eof())
|
||||
break;
|
||||
if(!fis.good()){
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(bad){
|
||||
infostream<<"Client: Failed to read texture from cache\""
|
||||
<<name<<"\""<<std::endl;
|
||||
}
|
||||
else {
|
||||
|
||||
SHA1 sha1;
|
||||
sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
|
||||
|
||||
unsigned char *digest = sha1.getDigest();
|
||||
|
||||
std::string digest_string = base64_encode(digest, 20);
|
||||
|
||||
if (digest_string == sha1_texture) {
|
||||
// Silly irrlicht's const-incorrectness
|
||||
Buffer<char> data_rw(tmp_os.str().c_str(), tmp_os.str().size());
|
||||
|
||||
// Create an irrlicht memory file
|
||||
io::IReadFile *rfile = irrfs->createMemoryReadFile(
|
||||
*data_rw, tmp_os.str().size(), "_tempreadfile");
|
||||
assert(rfile);
|
||||
// Read image
|
||||
video::IImage *img = vdrv->createImageFromFile(rfile);
|
||||
if(!img){
|
||||
infostream<<"Client: Cannot create image from data of "
|
||||
<<"received texture \""<<name<<"\""<<std::endl;
|
||||
rfile->drop();
|
||||
}
|
||||
else {
|
||||
m_tsrc->insertSourceImage(name, img);
|
||||
img->drop();
|
||||
rfile->drop();
|
||||
|
||||
texture_found = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
infostream<<"Client::Texture cached sha1 hash not matching server hash: "
|
||||
<<name << ": server ->"<<sha1_texture <<" client -> "<<digest_string<<std::endl;
|
||||
}
|
||||
|
||||
free(digest);
|
||||
}
|
||||
}
|
||||
|
||||
//add texture request
|
||||
if (!texture_found) {
|
||||
infostream<<"Client: Adding texture to request list: \""
|
||||
<<name<<"\""<<std::endl;
|
||||
texture_requests.push_back(TextureRequest(name));
|
||||
}
|
||||
|
||||
}
|
||||
// Resume threads
|
||||
m_mesh_update_thread.setRun(true);
|
||||
m_mesh_update_thread.Start();
|
||||
|
||||
ClientEvent event;
|
||||
event.type = CE_TEXTURES_UPDATED;
|
||||
m_client_event_queue.push_back(event);
|
||||
|
||||
|
||||
//send Texture request
|
||||
/*
|
||||
u16 command
|
||||
u16 number of textures requested
|
||||
for each texture {
|
||||
u16 length of name
|
||||
string name
|
||||
}
|
||||
*/
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
u8 buf[12];
|
||||
|
||||
|
||||
// Write command
|
||||
writeU16(buf, TOSERVER_REQUEST_TEXTURES);
|
||||
os.write((char*)buf, 2);
|
||||
|
||||
writeU16(buf,texture_requests.size());
|
||||
os.write((char*)buf, 2);
|
||||
|
||||
|
||||
for(core::list<TextureRequest>::Iterator i = texture_requests.begin();
|
||||
i != texture_requests.end(); i++) {
|
||||
os<<serializeString(i->name);
|
||||
}
|
||||
|
||||
// Make data buffer
|
||||
std::string s = os.str();
|
||||
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
|
||||
// Send as reliable
|
||||
Send(0, data, true);
|
||||
infostream<<"Client: Sending request list to server " <<std::endl;
|
||||
}
|
||||
else if(command == TOCLIENT_TEXTURES)
|
||||
{
|
||||
io::IFileSystem *irrfs = m_device->getFileSystem();
|
||||
@@ -1272,6 +1444,14 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
for(int i=0; i<num_textures; i++){
|
||||
std::string name = deSerializeString(is);
|
||||
std::string data = deSerializeLongString(is);
|
||||
|
||||
// if name contains illegal characters, ignore the texture
|
||||
if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
|
||||
errorstream<<"Client: ignoring illegal texture name "
|
||||
<<"sent by server: \""<<name<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Silly irrlicht's const-incorrectness
|
||||
Buffer<char> data_rw(data.c_str(), data.size());
|
||||
// Create an irrlicht memory file
|
||||
@@ -1286,6 +1466,20 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
rfile->drop();
|
||||
continue;
|
||||
}
|
||||
|
||||
fs::CreateAllDirs(getTextureCacheDir());
|
||||
|
||||
std::string filename = getTextureCacheDir() + DIR_DELIM + name;
|
||||
std::ofstream outfile(filename.c_str(), std::ios_base::binary | std::ios_base::trunc);
|
||||
|
||||
if (outfile.good()) {
|
||||
outfile.write(data.c_str(),data.length());
|
||||
outfile.close();
|
||||
}
|
||||
else {
|
||||
errorstream<<"Client: Unable to open cached texture file "<< filename <<std::endl;
|
||||
}
|
||||
|
||||
m_tsrc->insertSourceImage(name, img);
|
||||
img->drop();
|
||||
rfile->drop();
|
||||
@@ -1782,6 +1976,34 @@ InventoryContext *Client::getInventoryContext()
|
||||
return &m_inventory_context;
|
||||
}
|
||||
|
||||
Inventory* Client::getInventory(const InventoryLocation &loc)
|
||||
{
|
||||
switch(loc.type){
|
||||
case InventoryLocation::UNDEFINED:
|
||||
{}
|
||||
break;
|
||||
case InventoryLocation::PLAYER:
|
||||
{
|
||||
Player *player = m_env.getPlayer(loc.name.c_str());
|
||||
if(!player)
|
||||
return NULL;
|
||||
return &player->inventory;
|
||||
}
|
||||
break;
|
||||
case InventoryLocation::NODEMETA:
|
||||
{
|
||||
NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
|
||||
if(!meta)
|
||||
return NULL;
|
||||
return meta->getInventory();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#if 0
|
||||
Inventory* Client::getInventory(InventoryContext *c, std::string id)
|
||||
{
|
||||
if(id == "current_player")
|
||||
@@ -1810,6 +2032,7 @@ Inventory* Client::getInventory(InventoryContext *c, std::string id)
|
||||
infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
void Client::inventoryAction(InventoryAction *a)
|
||||
{
|
||||
sendInventoryAction(a);
|
||||
|
||||
@@ -30,6 +30,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "clientobject.h"
|
||||
#include "utility.h" // For IntervalLimiter
|
||||
#include "gamedef.h"
|
||||
#include "inventorymanager.h"
|
||||
#include "filesys.h"
|
||||
|
||||
struct MeshMakeData;
|
||||
class IGameDef;
|
||||
@@ -245,7 +247,9 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
|
||||
|
||||
InventoryContext *getInventoryContext();
|
||||
|
||||
Inventory* getInventory(InventoryContext *c, std::string id);
|
||||
/* InventoryManager interface */
|
||||
Inventory* getInventory(const InventoryLocation &loc);
|
||||
//Inventory* getInventory(InventoryContext *c, std::string id);
|
||||
void inventoryAction(InventoryAction *a);
|
||||
|
||||
// Gets closest object pointed by the shootline
|
||||
|
||||
@@ -37,15 +37,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
Obsolete TOSERVER_GROUND_ACTION
|
||||
PROTOCOL_VERSION 5:
|
||||
Make players to be handled mostly as ActiveObjects
|
||||
PROTOCOL_VERSION 6:
|
||||
Only non-cached textures are sent
|
||||
*/
|
||||
|
||||
#define PROTOCOL_VERSION 5
|
||||
#define PROTOCOL_VERSION 6
|
||||
|
||||
#define PROTOCOL_ID 0x4f457403
|
||||
|
||||
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
|
||||
// base64-encoded SHA-1 (27+\0).
|
||||
|
||||
#define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_."
|
||||
|
||||
enum ToClientCommand
|
||||
{
|
||||
TOCLIENT_INIT = 0x10,
|
||||
@@ -235,6 +239,19 @@ enum ToClientCommand
|
||||
u32 length of the next item
|
||||
serialized CraftiItemDefManager
|
||||
*/
|
||||
|
||||
TOCLIENT_ANNOUNCE_TEXTURES = 0x3c,
|
||||
|
||||
/*
|
||||
u16 command
|
||||
u32 number of textures
|
||||
for each texture {
|
||||
u16 length of name
|
||||
string name
|
||||
u16 length of sha1_digest
|
||||
string sha1_digest
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
enum ToServerCommand
|
||||
@@ -408,6 +425,17 @@ enum ToServerCommand
|
||||
(Obsoletes TOSERVER_GROUND_ACTION and TOSERVER_CLICK_ACTIVEOBJECT.)
|
||||
*/
|
||||
|
||||
TOSERVER_REQUEST_TEXTURES = 0x40,
|
||||
|
||||
/*
|
||||
u16 command
|
||||
u16 number of textures requested
|
||||
for each texture {
|
||||
u16 length of name
|
||||
string name
|
||||
}
|
||||
*/
|
||||
|
||||
};
|
||||
|
||||
inline SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time)
|
||||
|
||||
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "settings.h"
|
||||
#include <ICameraSceneNode.h>
|
||||
#include <ITextSceneNode.h>
|
||||
#include <IBillboardSceneNode.h>
|
||||
#include "serialization.h" // For decompressZlib
|
||||
#include "gamedef.h"
|
||||
#include "clientobject.h"
|
||||
@@ -30,7 +31,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "mesh.h"
|
||||
#include "utility.h" // For IntervalLimiter
|
||||
class Settings;
|
||||
#include "MyBillboardSceneNode.h"
|
||||
|
||||
core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
|
||||
|
||||
@@ -332,6 +332,15 @@ class FireflyCAO : public ClientActiveObject
|
||||
SmoothTranslator pos_translator;
|
||||
};
|
||||
|
||||
static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill,
|
||||
float txs, float tys, int col, int row)
|
||||
{
|
||||
video::SMaterial& material = bill->getMaterial(0);
|
||||
core::matrix4& matrix = material.getTextureMatrix(0);
|
||||
matrix.setTextureTranslate(txs*col, tys*row);
|
||||
matrix.setTextureScale(txs, tys);
|
||||
}
|
||||
|
||||
/*
|
||||
MobV2CAO
|
||||
*/
|
||||
@@ -377,7 +386,7 @@ class MobV2CAO : public ClientActiveObject
|
||||
|
||||
IntervalLimiter m_attack_interval;
|
||||
core::aabbox3d<f32> m_selection_box;
|
||||
scene::MyBillboardSceneNode *m_node;
|
||||
scene::IBillboardSceneNode *m_node;
|
||||
v3f m_position;
|
||||
std::string m_texture_name;
|
||||
float m_yaw;
|
||||
@@ -1305,8 +1314,8 @@ void MobV2CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
|
||||
std::string texture_string = m_texture_name +
|
||||
"^[makealpha:128,0,0^[makealpha:128,128,0";
|
||||
|
||||
scene::MyBillboardSceneNode *bill = new scene::MyBillboardSceneNode(
|
||||
smgr->getRootSceneNode(), smgr, -1, v3f(0,0,0), v2f(1,1));
|
||||
scene::IBillboardSceneNode *bill = smgr->addBillboardSceneNode(
|
||||
NULL, v2f(1, 1), v3f(0,0,0), -1);
|
||||
bill->setMaterialTexture(0, tsrc->getTextureRaw(texture_string));
|
||||
bill->setMaterialFlag(video::EMF_LIGHTING, false);
|
||||
bill->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
@@ -1320,17 +1329,11 @@ void MobV2CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
|
||||
const float txs = txp*32;
|
||||
const float typ = 1./240;
|
||||
const float tys = typ*48;
|
||||
bill->setTCoords(0, v2f(txs*1, tys*1));
|
||||
bill->setTCoords(1, v2f(txs*1, tys*0));
|
||||
bill->setTCoords(2, v2f(txs*0, tys*0));
|
||||
bill->setTCoords(3, v2f(txs*0, tys*1));
|
||||
setBillboardTextureMatrix(bill, txs, tys, 0, 0);
|
||||
} else if(m_sprite_type == "simple"){
|
||||
const float txs = 1.0;
|
||||
const float tys = 1.0 / m_simple_anim_frames;
|
||||
bill->setTCoords(0, v2f(txs*1, tys*1));
|
||||
bill->setTCoords(1, v2f(txs*1, tys*0));
|
||||
bill->setTCoords(2, v2f(txs*0, tys*0));
|
||||
bill->setTCoords(3, v2f(txs*0, tys*1));
|
||||
setBillboardTextureMatrix(bill, txs, tys, 0, 0);
|
||||
} else {
|
||||
infostream<<"MobV2CAO: Unknown sprite type \""<<m_sprite_type<<"\""
|
||||
<<std::endl;
|
||||
@@ -1346,7 +1349,6 @@ void MobV2CAO::removeFromScene()
|
||||
if(m_node == NULL)
|
||||
return;
|
||||
|
||||
m_node->drop();
|
||||
m_node->remove();
|
||||
m_node = NULL;
|
||||
}
|
||||
@@ -1394,7 +1396,7 @@ void MobV2CAO::updateNodePos()
|
||||
|
||||
void MobV2CAO::step(float dtime, ClientEnvironment *env)
|
||||
{
|
||||
scene::MyBillboardSceneNode *bill = m_node;
|
||||
scene::IBillboardSceneNode *bill = m_node;
|
||||
if(!bill)
|
||||
return;
|
||||
|
||||
@@ -1447,10 +1449,7 @@ void MobV2CAO::step(float dtime, ClientEnvironment *env)
|
||||
const float txs = txp*32;
|
||||
const float typ = 1./240;
|
||||
const float tys = typ*48;
|
||||
bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
|
||||
bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
|
||||
bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
|
||||
bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
|
||||
setBillboardTextureMatrix(bill, txs, tys, col, row);
|
||||
} else if(m_sprite_type == "simple"){
|
||||
m_walk_timer += dtime;
|
||||
if(m_walk_timer >= m_simple_anim_frametime){
|
||||
@@ -1461,10 +1460,7 @@ void MobV2CAO::step(float dtime, ClientEnvironment *env)
|
||||
int row = m_walk_frame;
|
||||
const float txs = 1.0;
|
||||
const float tys = 1.0 / m_simple_anim_frames;
|
||||
bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
|
||||
bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
|
||||
bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
|
||||
bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
|
||||
setBillboardTextureMatrix(bill, txs, tys, col, row);
|
||||
} else {
|
||||
infostream<<"MobV2CAO::step(): Unknown sprite type \""
|
||||
<<m_sprite_type<<"\""<<std::endl;
|
||||
@@ -1677,7 +1673,7 @@ class LuaEntityCAO : public ClientActiveObject
|
||||
private:
|
||||
core::aabbox3d<f32> m_selection_box;
|
||||
scene::IMeshSceneNode *m_meshnode;
|
||||
scene::MyBillboardSceneNode *m_spritenode;
|
||||
scene::IBillboardSceneNode *m_spritenode;
|
||||
v3f m_position;
|
||||
v3f m_velocity;
|
||||
v3f m_acceleration;
|
||||
@@ -1783,8 +1779,8 @@ class LuaEntityCAO : public ClientActiveObject
|
||||
|
||||
if(m_prop->visual == "sprite"){
|
||||
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 = smgr->addBillboardSceneNode(
|
||||
NULL, v2f(1, 1), v3f(0,0,0), -1);
|
||||
m_spritenode->setMaterialTexture(0,
|
||||
tsrc->getTextureRaw("unknown_block.png"));
|
||||
m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
|
||||
@@ -1797,71 +1793,15 @@ class LuaEntityCAO : public ClientActiveObject
|
||||
{
|
||||
const float txs = 1.0 / 1;
|
||||
const float tys = 1.0 / 1;
|
||||
m_spritenode->setTCoords(0, v2f(txs*1, tys*1));
|
||||
m_spritenode->setTCoords(1, v2f(txs*1, tys*0));
|
||||
m_spritenode->setTCoords(2, v2f(txs*0, tys*0));
|
||||
m_spritenode->setTCoords(3, v2f(txs*0, tys*1));
|
||||
setBillboardTextureMatrix(m_spritenode,
|
||||
txs, tys, 0, 0);
|
||||
}
|
||||
} else if(m_prop->visual == "cube"){
|
||||
infostream<<"LuaEntityCAO::addToScene(): cube"<<std::endl;
|
||||
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),
|
||||
};
|
||||
|
||||
for(u32 i=0; i<24; ++i){
|
||||
vertices[i].Pos *= BS;
|
||||
vertices[i].Pos.Y *= m_prop->visual_size.Y;
|
||||
vertices[i].Pos.X *= m_prop->visual_size.X;
|
||||
vertices[i].Pos.Z *= m_prop->visual_size.X;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
|
||||
m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
|
||||
mesh->drop();
|
||||
|
||||
m_meshnode->setMesh(mesh);
|
||||
m_meshnode->setScale(v3f(1));
|
||||
// Will be shown when we know the brightness
|
||||
m_meshnode->setVisible(false);
|
||||
@@ -1999,10 +1939,8 @@ class LuaEntityCAO : public ClientActiveObject
|
||||
|
||||
float txs = m_tx_size.X;
|
||||
float tys = m_tx_size.Y;
|
||||
m_spritenode->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
|
||||
m_spritenode->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
|
||||
m_spritenode->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
|
||||
m_spritenode->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
|
||||
setBillboardTextureMatrix(m_spritenode,
|
||||
txs, tys, col, row);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -722,14 +722,14 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
// Wall at X+ of node
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
|
||||
ap.x0(), ap.y1()),
|
||||
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
|
||||
ap.x1(), ap.y1()),
|
||||
video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c,
|
||||
ap.x1(), ap.y0()),
|
||||
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
|
||||
ap.x0(), ap.y0()),
|
||||
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
|
||||
ap.x1(), ap.y0()),
|
||||
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
|
||||
ap.x1(), ap.y1()),
|
||||
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
|
||||
ap.x0(), ap.y1()),
|
||||
};
|
||||
|
||||
v3s16 dir = unpackDir(n.param2);
|
||||
|
||||
@@ -1658,8 +1658,11 @@ std::string LuaEntitySAO::getStaticData()
|
||||
|
||||
void LuaEntitySAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
|
||||
{
|
||||
if(!m_registered)
|
||||
if(!m_registered){
|
||||
// Delete unknown LuaEntities when punched
|
||||
m_removed = true;
|
||||
return;
|
||||
}
|
||||
lua_State *L = m_env->getLua();
|
||||
scriptapi_luaentity_punch(L, m_id, puncher, time_from_last_punch);
|
||||
}
|
||||
@@ -1695,6 +1698,11 @@ void LuaEntitySAO::setVelocity(v3f velocity)
|
||||
m_velocity = velocity;
|
||||
}
|
||||
|
||||
v3f LuaEntitySAO::getVelocity()
|
||||
{
|
||||
return m_velocity;
|
||||
}
|
||||
|
||||
void LuaEntitySAO::setAcceleration(v3f acceleration)
|
||||
{
|
||||
m_acceleration = acceleration;
|
||||
@@ -1705,6 +1713,16 @@ v3f LuaEntitySAO::getAcceleration()
|
||||
return m_acceleration;
|
||||
}
|
||||
|
||||
void LuaEntitySAO::setYaw(float yaw)
|
||||
{
|
||||
m_yaw = yaw;
|
||||
}
|
||||
|
||||
float LuaEntitySAO::getYaw()
|
||||
{
|
||||
return m_yaw;
|
||||
}
|
||||
|
||||
void LuaEntitySAO::setTextureMod(const std::string &mod)
|
||||
{
|
||||
std::ostringstream os(std::ios::binary);
|
||||
@@ -1733,6 +1751,11 @@ void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
std::string LuaEntitySAO::getName()
|
||||
{
|
||||
return m_init_name;
|
||||
}
|
||||
|
||||
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
|
||||
{
|
||||
m_last_sent_move_precision = m_base_position.getDistanceFrom(
|
||||
|
||||
@@ -213,11 +213,15 @@ class LuaEntitySAO : public ServerActiveObject
|
||||
float getMinimumSavedMovement();
|
||||
/* LuaEntitySAO-specific */
|
||||
void setVelocity(v3f velocity);
|
||||
v3f getVelocity();
|
||||
void setAcceleration(v3f acceleration);
|
||||
v3f getAcceleration();
|
||||
void setYaw(float yaw);
|
||||
float getYaw();
|
||||
void setTextureMod(const std::string &mod);
|
||||
void setSprite(v2s16 p, int num_frames, float framelength,
|
||||
bool select_horiz_by_yawpitch);
|
||||
std::string getName();
|
||||
private:
|
||||
void sendPosition(bool do_interpolate, bool is_movement_end);
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "utility.h"
|
||||
#include "gamedef.h"
|
||||
#include "inventory.h"
|
||||
#include "inventorymanager.h" // checkItemCombination
|
||||
|
||||
CraftPointerInput::~CraftPointerInput()
|
||||
{
|
||||
|
||||
@@ -203,6 +203,22 @@ u32 Environment::getDayNightRatio()
|
||||
return time_to_daynight_ratio(m_time_of_day);
|
||||
}
|
||||
|
||||
/*
|
||||
ABMWithState
|
||||
*/
|
||||
|
||||
ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
|
||||
abm(abm_),
|
||||
timer(0)
|
||||
{
|
||||
// Initialize timer to random value to spread processing
|
||||
float itv = abm->getTriggerInterval();
|
||||
itv = MYMAX(0.001, itv); // No less than 1ms
|
||||
int minval = MYMAX(-0.51*itv, -60); // Clamp to
|
||||
int maxval = MYMIN(0.51*itv, 60); // +-60 seconds
|
||||
timer = myrand_range(minval, maxval);
|
||||
}
|
||||
|
||||
/*
|
||||
ActiveBlockList
|
||||
*/
|
||||
@@ -588,15 +604,17 @@ class ABMHandler
|
||||
float trigger_interval = abm->getTriggerInterval();
|
||||
if(trigger_interval < 0.001)
|
||||
trigger_interval = 0.001;
|
||||
float actual_interval = dtime_s;
|
||||
if(use_timers){
|
||||
i->timer += dtime_s;
|
||||
if(i->timer < trigger_interval)
|
||||
continue;
|
||||
i->timer -= trigger_interval;
|
||||
actual_interval = trigger_interval;
|
||||
}
|
||||
ActiveABM aabm;
|
||||
aabm.abm = abm;
|
||||
float intervals = dtime_s / trigger_interval;
|
||||
float intervals = actual_interval / trigger_interval;
|
||||
float chance = abm->getTriggerChance();
|
||||
if(chance == 0)
|
||||
chance = 1;
|
||||
@@ -752,6 +770,23 @@ void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm)
|
||||
m_abms.push_back(ABMWithState(abm));
|
||||
}
|
||||
|
||||
std::set<u16> ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius)
|
||||
{
|
||||
std::set<u16> objects;
|
||||
for(core::map<u16, ServerActiveObject*>::Iterator
|
||||
i = m_active_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
ServerActiveObject* obj = i.getNode()->getValue();
|
||||
u16 id = i.getNode()->getKey();
|
||||
v3f objectpos = obj->getBasePosition();
|
||||
if(objectpos.getDistanceFrom(pos) > radius)
|
||||
continue;
|
||||
objects.insert(id);
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
void ServerEnvironment::clearAllObjects()
|
||||
{
|
||||
infostream<<"ServerEnvironment::clearAllObjects(): "
|
||||
|
||||
@@ -129,9 +129,7 @@ struct ABMWithState
|
||||
ActiveBlockModifier *abm;
|
||||
float timer;
|
||||
|
||||
ABMWithState(ActiveBlockModifier *abm_):
|
||||
abm(abm_)
|
||||
{}
|
||||
ABMWithState(ActiveBlockModifier *abm_);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -261,18 +259,24 @@ class ServerEnvironment : public Environment
|
||||
void activateBlock(MapBlock *block, u32 additional_dtime=0);
|
||||
|
||||
/*
|
||||
ActiveBlockModifiers (TODO)
|
||||
ActiveBlockModifiers
|
||||
-------------------------------------------
|
||||
NOTE: Not used currently (TODO: Use or remove)
|
||||
*/
|
||||
|
||||
void addActiveBlockModifier(ActiveBlockModifier *abm);
|
||||
|
||||
/* Other stuff */
|
||||
/*
|
||||
Other stuff
|
||||
-------------------------------------------
|
||||
*/
|
||||
|
||||
// Find all active objects inside a radius around a point
|
||||
std::set<u16> getObjectsInsideRadius(v3f pos, float radius);
|
||||
|
||||
// Clear all objects, loading and going through every MapBlock
|
||||
void clearAllObjects();
|
||||
|
||||
// This makes stuff happen
|
||||
void step(f32 dtime);
|
||||
|
||||
private:
|
||||
|
||||
@@ -190,10 +190,36 @@ std::vector<DirListNode> GetDirListing(std::string pathstring)
|
||||
if(dirp->d_name[0]!='.'){
|
||||
DirListNode node;
|
||||
node.name = dirp->d_name;
|
||||
if(dirp->d_type == DT_DIR) node.dir = true;
|
||||
else node.dir = false;
|
||||
if(node.name != "." && node.name != "..")
|
||||
listing.push_back(node);
|
||||
if(node.name == "." || node.name == "..")
|
||||
continue;
|
||||
|
||||
int isdir = -1; // -1 means unknown
|
||||
|
||||
/*
|
||||
POSIX doesn't define d_type member of struct dirent and
|
||||
certain filesystems on glibc/Linux will only return
|
||||
DT_UNKNOWN for the d_type member.
|
||||
|
||||
Also we don't know whether symlinks are directories or not.
|
||||
*/
|
||||
#ifdef _DIRENT_HAVE_D_TYPE
|
||||
if(dirp->d_type != DT_UNKNOWN && dirp->d_type != DT_LNK)
|
||||
isdir = (dirp->d_type == DT_DIR);
|
||||
#endif /* _DIRENT_HAVE_D_TYPE */
|
||||
|
||||
/*
|
||||
Was d_type DT_UNKNOWN, DT_LNK or nonexistent?
|
||||
If so, try stat().
|
||||
*/
|
||||
if(isdir == -1)
|
||||
{
|
||||
struct stat statbuf;
|
||||
if (stat((pathstring + "/" + node.name).c_str(), &statbuf))
|
||||
continue;
|
||||
isdir = ((statbuf.st_mode & S_IFDIR) == S_IFDIR);
|
||||
}
|
||||
node.dir = isdir;
|
||||
listing.push_back(node);
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
|
||||
12
src/game.cpp
12
src/game.cpp
@@ -824,7 +824,7 @@ void the_game(
|
||||
bool got_content = false;
|
||||
{
|
||||
float frametime = 0.033;
|
||||
const float timeout = 5.0;
|
||||
const float timeout = 30.0;
|
||||
float time_counter = 0.0;
|
||||
for(;;)
|
||||
{
|
||||
@@ -1011,6 +1011,7 @@ void the_game(
|
||||
bool invert_mouse = g_settings->getBool("invert_mouse");
|
||||
|
||||
bool respawn_menu_active = false;
|
||||
bool update_wielded_item_trigger = false;
|
||||
|
||||
bool show_profiler = false;
|
||||
bool force_fog_off = false;
|
||||
@@ -1663,6 +1664,8 @@ void the_game(
|
||||
else if(event.type == CE_TEXTURES_UPDATED)
|
||||
{
|
||||
update_skybox(driver, tsrc, smgr, skybox, brightness);
|
||||
|
||||
update_wielded_item_trigger = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2274,7 +2277,12 @@ void the_game(
|
||||
{
|
||||
//infostream<<"Updating local inventory"<<std::endl;
|
||||
client.getLocalInventory(local_inventory);
|
||||
|
||||
|
||||
update_wielded_item_trigger = true;
|
||||
}
|
||||
if(update_wielded_item_trigger)
|
||||
{
|
||||
update_wielded_item_trigger = false;
|
||||
// Update wielded tool
|
||||
InventoryList *mlist = local_inventory.getList("main");
|
||||
InventoryItem *item = NULL;
|
||||
|
||||
@@ -29,6 +29,7 @@ class IRespawnInitiator
|
||||
{
|
||||
public:
|
||||
virtual void respawn() = 0;
|
||||
virtual ~IRespawnInitiator() {};
|
||||
};
|
||||
|
||||
class GUIDeathScreen : public GUIModalMenu
|
||||
|
||||
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <IGUIStaticText.h>
|
||||
#include <IGUIFont.h>
|
||||
#include "log.h"
|
||||
#include "inventorymanager.h"
|
||||
|
||||
void drawInventoryItem(video::IVideoDriver *driver,
|
||||
gui::IGUIFont *font,
|
||||
|
||||
@@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "modalMenu.h"
|
||||
|
||||
class ITextureSource;
|
||||
class InventoryContext;
|
||||
class InventoryManager;
|
||||
|
||||
void drawInventoryItem(video::IVideoDriver *driver,
|
||||
gui::IGUIFont *font,
|
||||
|
||||
@@ -85,7 +85,7 @@ void GUIMessageMenu::regenerateGui(v2u32 screensize)
|
||||
Add stuff
|
||||
*/
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 400, 50);
|
||||
core::rect<s32> rect(0, 0, 400, 70);
|
||||
rect = rect + v2s32(size.X/2-400/2, size.Y/2-50/2-25);
|
||||
Environment->addStaticText(m_message_text.c_str(), rect, false,
|
||||
true, this, 256);
|
||||
@@ -93,7 +93,7 @@ void GUIMessageMenu::regenerateGui(v2u32 screensize)
|
||||
changeCtype("");
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 140, 30);
|
||||
rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+25);
|
||||
rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+45);
|
||||
gui::IGUIElement *e =
|
||||
Environment->addButton(rect, this, 257,
|
||||
wgettext("Proceed"));
|
||||
|
||||
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
struct TextDest
|
||||
{
|
||||
virtual void gotText(std::wstring text) = 0;
|
||||
virtual ~TextDest() {};
|
||||
};
|
||||
|
||||
class GUITextInputMenu : public GUIModalMenu
|
||||
|
||||
@@ -37,7 +37,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "scriptapi.h"
|
||||
#include "strfnd.h"
|
||||
#include "nameidmapping.h" // For loading legacy MaterialItems
|
||||
#include "serverremoteplayer.h"
|
||||
|
||||
/*
|
||||
InventoryItem
|
||||
@@ -246,7 +245,9 @@ MaterialItem::MaterialItem(IGameDef *gamedef, std::string nodename, u16 count):
|
||||
{
|
||||
if(nodename == "")
|
||||
nodename = "unknown_block";
|
||||
m_nodename = nodename;
|
||||
|
||||
// Convert directly to the correct name through aliases
|
||||
m_nodename = gamedef->ndef()->getAlias(nodename);
|
||||
}
|
||||
// Legacy constructor
|
||||
MaterialItem::MaterialItem(IGameDef *gamedef, content_t content, u16 count):
|
||||
@@ -309,6 +310,15 @@ content_t MaterialItem::getMaterial() const
|
||||
ToolItem
|
||||
*/
|
||||
|
||||
ToolItem::ToolItem(IGameDef *gamedef, std::string toolname, u16 wear):
|
||||
InventoryItem(gamedef, 1)
|
||||
{
|
||||
// Convert directly to the correct name through aliases
|
||||
m_toolname = gamedef->tdef()->getAlias(toolname);
|
||||
|
||||
m_wear = wear;
|
||||
}
|
||||
|
||||
std::string ToolItem::getImageBasename() const
|
||||
{
|
||||
return m_gamedef->getToolDefManager()->getImagename(m_toolname);
|
||||
@@ -357,9 +367,7 @@ bool ToolItem::isKnown() const
|
||||
CraftItem::CraftItem(IGameDef *gamedef, std::string subname, u16 count):
|
||||
InventoryItem(gamedef, count)
|
||||
{
|
||||
// Convert directly to the correct name through aliases.
|
||||
// This is necessary because CraftItem callbacks are stored in
|
||||
// Lua refenced by their correct name
|
||||
// Convert directly to the correct name through aliases
|
||||
m_subname = gamedef->cidef()->getAlias(subname);
|
||||
}
|
||||
|
||||
@@ -558,6 +566,22 @@ void InventoryList::clearItems()
|
||||
//setDirty(true);
|
||||
}
|
||||
|
||||
void InventoryList::setSize(u32 newsize)
|
||||
{
|
||||
if(newsize < m_items.size()){
|
||||
for(u32 i=newsize; i<m_items.size(); i++){
|
||||
if(m_items[i])
|
||||
delete m_items[i];
|
||||
}
|
||||
m_items.erase(newsize, m_items.size() - newsize);
|
||||
} else {
|
||||
for(u32 i=m_items.size(); i<newsize; i++){
|
||||
m_items.push_back(NULL);
|
||||
}
|
||||
}
|
||||
m_size = newsize;
|
||||
}
|
||||
|
||||
void InventoryList::serialize(std::ostream &os) const
|
||||
{
|
||||
//os.imbue(std::locale("C"));
|
||||
@@ -1032,458 +1056,4 @@ const s32 Inventory::getListIndex(const std::string &name) const
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
InventoryAction
|
||||
*/
|
||||
|
||||
InventoryAction * InventoryAction::deSerialize(std::istream &is)
|
||||
{
|
||||
std::string type;
|
||||
std::getline(is, type, ' ');
|
||||
|
||||
InventoryAction *a = NULL;
|
||||
|
||||
if(type == "Move")
|
||||
{
|
||||
a = new IMoveAction(is);
|
||||
}
|
||||
else if(type == "Drop")
|
||||
{
|
||||
a = new IDropAction(is);
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static std::string describeC(const struct InventoryContext *c)
|
||||
{
|
||||
if(c->current_player == NULL)
|
||||
return "current_player=NULL";
|
||||
else
|
||||
return std::string("current_player=") + c->current_player->getName();
|
||||
}
|
||||
|
||||
IMoveAction::IMoveAction(std::istream &is)
|
||||
{
|
||||
std::string ts;
|
||||
|
||||
std::getline(is, ts, ' ');
|
||||
count = stoi(ts);
|
||||
|
||||
std::getline(is, from_inv, ' ');
|
||||
|
||||
std::getline(is, from_list, ' ');
|
||||
|
||||
std::getline(is, ts, ' ');
|
||||
from_i = stoi(ts);
|
||||
|
||||
std::getline(is, to_inv, ' ');
|
||||
|
||||
std::getline(is, to_list, ' ');
|
||||
|
||||
std::getline(is, ts, ' ');
|
||||
to_i = stoi(ts);
|
||||
}
|
||||
|
||||
void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
|
||||
ServerEnvironment *env)
|
||||
{
|
||||
Inventory *inv_from = mgr->getInventory(c, from_inv);
|
||||
Inventory *inv_to = mgr->getInventory(c, to_inv);
|
||||
|
||||
if(!inv_from){
|
||||
infostream<<"IMoveAction::apply(): FAIL: source inventory not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", to_inv=\""<<to_inv<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
if(!inv_to){
|
||||
infostream<<"IMoveAction::apply(): FAIL: destination inventory not found: "
|
||||
"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", to_inv=\""<<to_inv<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryList *list_from = inv_from->getList(from_list);
|
||||
InventoryList *list_to = inv_to->getList(to_list);
|
||||
|
||||
/*
|
||||
If a list doesn't exist or the source item doesn't exist
|
||||
*/
|
||||
if(!list_from){
|
||||
infostream<<"IMoveAction::apply(): FAIL: source list not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", from_list=\""<<from_list<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
if(!list_to){
|
||||
infostream<<"IMoveAction::apply(): FAIL: destination list not found: "
|
||||
<<"context=["<<describeC(c)<<"], to_inv=\""<<to_inv<<"\""
|
||||
<<", to_list=\""<<to_list<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
if(list_from->getItem(from_i) == NULL)
|
||||
{
|
||||
infostream<<"IMoveAction::apply(): FAIL: source item not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", from_list=\""<<from_list<<"\""
|
||||
<<" from_i="<<from_i<<std::endl;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
If the source and the destination slots are the same
|
||||
*/
|
||||
if(inv_from == inv_to && list_from == list_to && from_i == to_i)
|
||||
{
|
||||
infostream<<"IMoveAction::apply(): FAIL: source and destination slots "
|
||||
<<"are the same: inv=\""<<from_inv<<"\" list=\""<<from_list
|
||||
<<"\" i="<<from_i<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Take item from source list
|
||||
InventoryItem *item1 = NULL;
|
||||
if(count == 0)
|
||||
item1 = list_from->changeItem(from_i, NULL);
|
||||
else
|
||||
item1 = list_from->takeItem(from_i, count);
|
||||
|
||||
// Try to add the item to destination list
|
||||
InventoryItem *olditem = item1;
|
||||
item1 = list_to->addItem(to_i, item1);
|
||||
|
||||
// If something is returned, the item was not fully added
|
||||
if(item1 != NULL)
|
||||
{
|
||||
// If olditem is returned, nothing was added.
|
||||
bool nothing_added = (item1 == olditem);
|
||||
|
||||
// If something else is returned, part of the item was left unadded.
|
||||
// Add the other part back to the source item
|
||||
list_from->addItem(from_i, item1);
|
||||
|
||||
// If olditem is returned, nothing was added.
|
||||
// Swap the items
|
||||
if(nothing_added)
|
||||
{
|
||||
// Take item from source list
|
||||
item1 = list_from->changeItem(from_i, NULL);
|
||||
// Adding was not possible, swap the items.
|
||||
InventoryItem *item2 = list_to->changeItem(to_i, item1);
|
||||
// Put item from destination list to the source list
|
||||
list_from->changeItem(from_i, item2);
|
||||
}
|
||||
}
|
||||
|
||||
mgr->inventoryModified(c, from_inv);
|
||||
if(from_inv != to_inv)
|
||||
mgr->inventoryModified(c, to_inv);
|
||||
|
||||
infostream<<"IMoveAction::apply(): moved at "
|
||||
<<"["<<describeC(c)<<"]"
|
||||
<<" from inv=\""<<from_inv<<"\""
|
||||
<<" list=\""<<from_list<<"\""
|
||||
<<" i="<<from_i
|
||||
<<" to inv=\""<<to_inv<<"\""
|
||||
<<" list=\""<<to_list<<"\""
|
||||
<<" i="<<to_i
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
IDropAction::IDropAction(std::istream &is)
|
||||
{
|
||||
std::string ts;
|
||||
|
||||
std::getline(is, ts, ' ');
|
||||
count = stoi(ts);
|
||||
|
||||
std::getline(is, from_inv, ' ');
|
||||
|
||||
std::getline(is, from_list, ' ');
|
||||
|
||||
std::getline(is, ts, ' ');
|
||||
from_i = stoi(ts);
|
||||
}
|
||||
|
||||
void IDropAction::apply(InventoryContext *c, InventoryManager *mgr,
|
||||
ServerEnvironment *env)
|
||||
{
|
||||
if(c->current_player == NULL){
|
||||
infostream<<"IDropAction::apply(): FAIL: current_player is NULL"<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do NOT cast directly to ServerActiveObject*, it breaks
|
||||
// because of multiple inheritance.
|
||||
ServerActiveObject *dropper =
|
||||
static_cast<ServerActiveObject*>(
|
||||
static_cast<ServerRemotePlayer*>(
|
||||
c->current_player
|
||||
));
|
||||
|
||||
Inventory *inv_from = mgr->getInventory(c, from_inv);
|
||||
|
||||
if(!inv_from){
|
||||
infostream<<"IDropAction::apply(): FAIL: source inventory not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryList *list_from = inv_from->getList(from_list);
|
||||
|
||||
/*
|
||||
If a list doesn't exist or the source item doesn't exist
|
||||
*/
|
||||
if(!list_from){
|
||||
infostream<<"IDropAction::apply(): FAIL: source list not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", from_list=\""<<from_list<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
InventoryItem *item = list_from->getItem(from_i);
|
||||
if(item == NULL)
|
||||
{
|
||||
infostream<<"IDropAction::apply(): FAIL: source item not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", from_list=\""<<from_list<<"\""
|
||||
<<" from_i="<<from_i<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
v3f pos = dropper->getBasePosition();
|
||||
pos.Y += 0.5*BS;
|
||||
|
||||
s16 count2 = count;
|
||||
if(count2 == 0)
|
||||
count2 = -1;
|
||||
|
||||
/*
|
||||
Drop the item
|
||||
*/
|
||||
bool remove = item->dropOrPlace(env, dropper, pos, false, count2);
|
||||
if(remove)
|
||||
list_from->deleteItem(from_i);
|
||||
|
||||
mgr->inventoryModified(c, from_inv);
|
||||
|
||||
infostream<<"IDropAction::apply(): dropped "
|
||||
<<"["<<describeC(c)<<"]"
|
||||
<<" from inv=\""<<from_inv<<"\""
|
||||
<<" list=\""<<from_list<<"\""
|
||||
<<" i="<<from_i
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
/*
|
||||
Craft checking system
|
||||
*/
|
||||
|
||||
bool ItemSpec::checkItem(const InventoryItem *item) const
|
||||
{
|
||||
if(type == ITEM_NONE)
|
||||
{
|
||||
// Has to be no item
|
||||
if(item != NULL)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// There should be an item
|
||||
if(item == NULL)
|
||||
return false;
|
||||
|
||||
std::string itemname = item->getName();
|
||||
|
||||
if(type == ITEM_MATERIAL)
|
||||
{
|
||||
if(itemname != "MaterialItem")
|
||||
return false;
|
||||
MaterialItem *mitem = (MaterialItem*)item;
|
||||
if(num != 65535){
|
||||
if(mitem->getMaterial() != num)
|
||||
return false;
|
||||
} else {
|
||||
if(mitem->getNodeName() != name)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(type == ITEM_CRAFT)
|
||||
{
|
||||
if(itemname != "CraftItem")
|
||||
return false;
|
||||
CraftItem *mitem = (CraftItem*)item;
|
||||
if(mitem->getSubName() != name)
|
||||
return false;
|
||||
}
|
||||
else if(type == ITEM_TOOL)
|
||||
{
|
||||
// Not supported yet
|
||||
assert(0);
|
||||
}
|
||||
else if(type == ITEM_MBO)
|
||||
{
|
||||
// Not supported yet
|
||||
assert(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not supported yet
|
||||
assert(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkItemCombination(InventoryItem const * const *items, const ItemSpec *specs)
|
||||
{
|
||||
u16 items_min_x = 100;
|
||||
u16 items_max_x = 100;
|
||||
u16 items_min_y = 100;
|
||||
u16 items_max_y = 100;
|
||||
for(u16 y=0; y<3; y++)
|
||||
for(u16 x=0; x<3; x++)
|
||||
{
|
||||
if(items[y*3 + x] == NULL)
|
||||
continue;
|
||||
if(items_min_x == 100 || x < items_min_x)
|
||||
items_min_x = x;
|
||||
if(items_min_y == 100 || y < items_min_y)
|
||||
items_min_y = y;
|
||||
if(items_max_x == 100 || x > items_max_x)
|
||||
items_max_x = x;
|
||||
if(items_max_y == 100 || y > items_max_y)
|
||||
items_max_y = y;
|
||||
}
|
||||
// No items at all, just return false
|
||||
if(items_min_x == 100)
|
||||
return false;
|
||||
|
||||
u16 items_w = items_max_x - items_min_x + 1;
|
||||
u16 items_h = items_max_y - items_min_y + 1;
|
||||
|
||||
u16 specs_min_x = 100;
|
||||
u16 specs_max_x = 100;
|
||||
u16 specs_min_y = 100;
|
||||
u16 specs_max_y = 100;
|
||||
for(u16 y=0; y<3; y++)
|
||||
for(u16 x=0; x<3; x++)
|
||||
{
|
||||
if(specs[y*3 + x].type == ITEM_NONE)
|
||||
continue;
|
||||
if(specs_min_x == 100 || x < specs_min_x)
|
||||
specs_min_x = x;
|
||||
if(specs_min_y == 100 || y < specs_min_y)
|
||||
specs_min_y = y;
|
||||
if(specs_max_x == 100 || x > specs_max_x)
|
||||
specs_max_x = x;
|
||||
if(specs_max_y == 100 || y > specs_max_y)
|
||||
specs_max_y = y;
|
||||
}
|
||||
// No specs at all, just return false
|
||||
if(specs_min_x == 100)
|
||||
return false;
|
||||
|
||||
u16 specs_w = specs_max_x - specs_min_x + 1;
|
||||
u16 specs_h = specs_max_y - specs_min_y + 1;
|
||||
|
||||
// Different sizes
|
||||
if(items_w != specs_w || items_h != specs_h)
|
||||
return false;
|
||||
|
||||
for(u16 y=0; y<specs_h; y++)
|
||||
for(u16 x=0; x<specs_w; x++)
|
||||
{
|
||||
u16 items_x = items_min_x + x;
|
||||
u16 items_y = items_min_y + y;
|
||||
u16 specs_x = specs_min_x + x;
|
||||
u16 specs_y = specs_min_y + y;
|
||||
const InventoryItem *item = items[items_y * 3 + items_x];
|
||||
const ItemSpec &spec = specs[specs_y * 3 + specs_x];
|
||||
|
||||
if(spec.checkItem(item) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkItemCombination(const InventoryItem * const * items,
|
||||
const InventoryItem * const * specs)
|
||||
{
|
||||
u16 items_min_x = 100;
|
||||
u16 items_max_x = 100;
|
||||
u16 items_min_y = 100;
|
||||
u16 items_max_y = 100;
|
||||
for(u16 y=0; y<3; y++)
|
||||
for(u16 x=0; x<3; x++)
|
||||
{
|
||||
if(items[y*3 + x] == NULL)
|
||||
continue;
|
||||
if(items_min_x == 100 || x < items_min_x)
|
||||
items_min_x = x;
|
||||
if(items_min_y == 100 || y < items_min_y)
|
||||
items_min_y = y;
|
||||
if(items_max_x == 100 || x > items_max_x)
|
||||
items_max_x = x;
|
||||
if(items_max_y == 100 || y > items_max_y)
|
||||
items_max_y = y;
|
||||
}
|
||||
// No items at all, just return false
|
||||
if(items_min_x == 100)
|
||||
return false;
|
||||
|
||||
u16 items_w = items_max_x - items_min_x + 1;
|
||||
u16 items_h = items_max_y - items_min_y + 1;
|
||||
|
||||
u16 specs_min_x = 100;
|
||||
u16 specs_max_x = 100;
|
||||
u16 specs_min_y = 100;
|
||||
u16 specs_max_y = 100;
|
||||
for(u16 y=0; y<3; y++)
|
||||
for(u16 x=0; x<3; x++)
|
||||
{
|
||||
if(specs[y*3 + x] == NULL)
|
||||
continue;
|
||||
if(specs_min_x == 100 || x < specs_min_x)
|
||||
specs_min_x = x;
|
||||
if(specs_min_y == 100 || y < specs_min_y)
|
||||
specs_min_y = y;
|
||||
if(specs_max_x == 100 || x > specs_max_x)
|
||||
specs_max_x = x;
|
||||
if(specs_max_y == 100 || y > specs_max_y)
|
||||
specs_max_y = y;
|
||||
}
|
||||
// No specs at all, just return false
|
||||
if(specs_min_x == 100)
|
||||
return false;
|
||||
|
||||
u16 specs_w = specs_max_x - specs_min_x + 1;
|
||||
u16 specs_h = specs_max_y - specs_min_y + 1;
|
||||
|
||||
// Different sizes
|
||||
if(items_w != specs_w || items_h != specs_h)
|
||||
return false;
|
||||
|
||||
for(u16 y=0; y<specs_h; y++)
|
||||
for(u16 x=0; x<specs_w; x++)
|
||||
{
|
||||
u16 items_x = items_min_x + x;
|
||||
u16 items_y = items_min_y + y;
|
||||
u16 specs_x = specs_min_x + x;
|
||||
u16 specs_y = specs_min_y + y;
|
||||
const InventoryItem *item = items[items_y * 3 + items_x];
|
||||
const InventoryItem *spec = specs[specs_y * 3 + specs_x];
|
||||
|
||||
if(item == NULL && spec == NULL)
|
||||
continue;
|
||||
if(item == NULL && spec != NULL)
|
||||
return false;
|
||||
if(item != NULL && spec == NULL)
|
||||
return false;
|
||||
if(!spec->isSubsetOf(item))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//END
|
||||
|
||||
184
src/inventory.h
184
src/inventory.h
@@ -331,12 +331,7 @@ class CraftItem : public InventoryItem
|
||||
class ToolItem : public InventoryItem
|
||||
{
|
||||
public:
|
||||
ToolItem(IGameDef *gamedef, std::string toolname, u16 wear):
|
||||
InventoryItem(gamedef, 1)
|
||||
{
|
||||
m_toolname = toolname;
|
||||
m_wear = wear;
|
||||
}
|
||||
ToolItem(IGameDef *gamedef, std::string toolname, u16 wear);
|
||||
/*
|
||||
Implementation interface
|
||||
*/
|
||||
@@ -424,6 +419,7 @@ class InventoryList
|
||||
InventoryList(std::string name, u32 size);
|
||||
~InventoryList();
|
||||
void clearItems();
|
||||
void setSize(u32 newsize);
|
||||
void serialize(std::ostream &os) const;
|
||||
void deSerialize(std::istream &is, IGameDef *gamedef);
|
||||
|
||||
@@ -518,181 +514,5 @@ class Inventory
|
||||
core::array<InventoryList*> m_lists;
|
||||
};
|
||||
|
||||
class Player;
|
||||
|
||||
struct InventoryContext
|
||||
{
|
||||
Player *current_player;
|
||||
|
||||
InventoryContext():
|
||||
current_player(NULL)
|
||||
{}
|
||||
};
|
||||
|
||||
struct InventoryAction;
|
||||
|
||||
class InventoryManager
|
||||
{
|
||||
public:
|
||||
InventoryManager(){}
|
||||
virtual ~InventoryManager(){}
|
||||
|
||||
/*
|
||||
Get a pointer to an inventory specified by id.
|
||||
id can be:
|
||||
- "current_player"
|
||||
- "nodemeta:X,Y,Z"
|
||||
*/
|
||||
virtual Inventory* getInventory(InventoryContext *c, std::string id)
|
||||
{return NULL;}
|
||||
// Used on the server by InventoryAction::apply and other stuff
|
||||
virtual void inventoryModified(InventoryContext *c, std::string id)
|
||||
{}
|
||||
// Used on the client
|
||||
virtual void inventoryAction(InventoryAction *a)
|
||||
{}
|
||||
};
|
||||
|
||||
#define IACTION_MOVE 0
|
||||
#define IACTION_DROP 1
|
||||
|
||||
struct InventoryAction
|
||||
{
|
||||
static InventoryAction * deSerialize(std::istream &is);
|
||||
|
||||
virtual u16 getType() const = 0;
|
||||
virtual void serialize(std::ostream &os) const = 0;
|
||||
virtual void apply(InventoryContext *c, InventoryManager *mgr,
|
||||
ServerEnvironment *env) = 0;
|
||||
};
|
||||
|
||||
struct IMoveAction : public InventoryAction
|
||||
{
|
||||
// count=0 means "everything"
|
||||
u16 count;
|
||||
std::string from_inv;
|
||||
std::string from_list;
|
||||
s16 from_i;
|
||||
std::string to_inv;
|
||||
std::string to_list;
|
||||
s16 to_i;
|
||||
|
||||
IMoveAction()
|
||||
{
|
||||
count = 0;
|
||||
from_i = -1;
|
||||
to_i = -1;
|
||||
}
|
||||
|
||||
IMoveAction(std::istream &is);
|
||||
|
||||
u16 getType() const
|
||||
{
|
||||
return IACTION_MOVE;
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os) const
|
||||
{
|
||||
os<<"Move ";
|
||||
os<<count<<" ";
|
||||
os<<from_inv<<" ";
|
||||
os<<from_list<<" ";
|
||||
os<<from_i<<" ";
|
||||
os<<to_inv<<" ";
|
||||
os<<to_list<<" ";
|
||||
os<<to_i;
|
||||
}
|
||||
|
||||
void apply(InventoryContext *c, InventoryManager *mgr,
|
||||
ServerEnvironment *env);
|
||||
};
|
||||
|
||||
struct IDropAction : public InventoryAction
|
||||
{
|
||||
// count=0 means "everything"
|
||||
u16 count;
|
||||
std::string from_inv;
|
||||
std::string from_list;
|
||||
s16 from_i;
|
||||
|
||||
IDropAction()
|
||||
{
|
||||
count = 0;
|
||||
from_i = -1;
|
||||
}
|
||||
|
||||
IDropAction(std::istream &is);
|
||||
|
||||
u16 getType() const
|
||||
{
|
||||
return IACTION_DROP;
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os) const
|
||||
{
|
||||
os<<"Drop ";
|
||||
os<<count<<" ";
|
||||
os<<from_inv<<" ";
|
||||
os<<from_list<<" ";
|
||||
os<<from_i;
|
||||
}
|
||||
|
||||
void apply(InventoryContext *c, InventoryManager *mgr,
|
||||
ServerEnvironment *env);
|
||||
};
|
||||
|
||||
/*
|
||||
Craft checking system
|
||||
*/
|
||||
|
||||
enum ItemSpecType
|
||||
{
|
||||
ITEM_NONE,
|
||||
ITEM_MATERIAL,
|
||||
ITEM_CRAFT,
|
||||
ITEM_TOOL,
|
||||
ITEM_MBO
|
||||
};
|
||||
|
||||
struct ItemSpec
|
||||
{
|
||||
enum ItemSpecType type;
|
||||
// Only other one of these is used
|
||||
std::string name;
|
||||
u16 num;
|
||||
|
||||
ItemSpec():
|
||||
type(ITEM_NONE)
|
||||
{
|
||||
}
|
||||
ItemSpec(enum ItemSpecType a_type, std::string a_name):
|
||||
type(a_type),
|
||||
name(a_name),
|
||||
num(65535)
|
||||
{
|
||||
}
|
||||
ItemSpec(enum ItemSpecType a_type, u16 a_num):
|
||||
type(a_type),
|
||||
name(""),
|
||||
num(a_num)
|
||||
{
|
||||
}
|
||||
|
||||
bool checkItem(const InventoryItem *item) const;
|
||||
};
|
||||
|
||||
/*
|
||||
items: a pointer to an array of 9 pointers to items
|
||||
specs: a pointer to an array of 9 ItemSpecs
|
||||
*/
|
||||
bool checkItemCombination(const InventoryItem * const*items, const ItemSpec *specs);
|
||||
|
||||
/*
|
||||
items: a pointer to an array of 9 pointers to items
|
||||
specs: a pointer to an array of 9 pointers to items
|
||||
*/
|
||||
bool checkItemCombination(const InventoryItem * const * items,
|
||||
const InventoryItem * const * specs);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
544
src/inventorymanager.cpp
Normal file
544
src/inventorymanager.cpp
Normal file
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
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 "inventorymanager.h"
|
||||
#include "serverremoteplayer.h"
|
||||
#include "log.h"
|
||||
#include "mapblock.h" // getNodeBlockPos
|
||||
|
||||
/*
|
||||
InventoryManager
|
||||
*/
|
||||
|
||||
// Wrapper for old code
|
||||
Inventory* InventoryManager::getInventory(InventoryContext *c, std::string id)
|
||||
{
|
||||
if(id == "current_player")
|
||||
{
|
||||
assert(c->current_player);
|
||||
InventoryLocation loc;
|
||||
loc.setPlayer(c->current_player->getName());
|
||||
return getInventory(loc);
|
||||
}
|
||||
|
||||
Strfnd fn(id);
|
||||
std::string id0 = fn.next(":");
|
||||
|
||||
if(id0 == "nodemeta")
|
||||
{
|
||||
v3s16 p;
|
||||
p.X = stoi(fn.next(","));
|
||||
p.Y = stoi(fn.next(","));
|
||||
p.Z = stoi(fn.next(","));
|
||||
|
||||
InventoryLocation loc;
|
||||
loc.setNodeMeta(p);
|
||||
return getInventory(loc);
|
||||
}
|
||||
|
||||
errorstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
|
||||
return NULL;
|
||||
}
|
||||
// Wrapper for old code
|
||||
void InventoryManager::inventoryModified(InventoryContext *c, std::string id)
|
||||
{
|
||||
if(id == "current_player")
|
||||
{
|
||||
assert(c->current_player);
|
||||
InventoryLocation loc;
|
||||
loc.setPlayer(c->current_player->getName());
|
||||
setInventoryModified(loc);
|
||||
return;
|
||||
}
|
||||
|
||||
Strfnd fn(id);
|
||||
std::string id0 = fn.next(":");
|
||||
|
||||
if(id0 == "nodemeta")
|
||||
{
|
||||
v3s16 p;
|
||||
p.X = stoi(fn.next(","));
|
||||
p.Y = stoi(fn.next(","));
|
||||
p.Z = stoi(fn.next(","));
|
||||
v3s16 blockpos = getNodeBlockPos(p);
|
||||
|
||||
InventoryLocation loc;
|
||||
loc.setNodeMeta(p);
|
||||
setInventoryModified(loc);
|
||||
return;
|
||||
}
|
||||
|
||||
errorstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
|
||||
}
|
||||
|
||||
/*
|
||||
InventoryAction
|
||||
*/
|
||||
|
||||
InventoryAction * InventoryAction::deSerialize(std::istream &is)
|
||||
{
|
||||
std::string type;
|
||||
std::getline(is, type, ' ');
|
||||
|
||||
InventoryAction *a = NULL;
|
||||
|
||||
if(type == "Move")
|
||||
{
|
||||
a = new IMoveAction(is);
|
||||
}
|
||||
else if(type == "Drop")
|
||||
{
|
||||
a = new IDropAction(is);
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static std::string describeC(const struct InventoryContext *c)
|
||||
{
|
||||
if(c->current_player == NULL)
|
||||
return "current_player=NULL";
|
||||
else
|
||||
return std::string("current_player=") + c->current_player->getName();
|
||||
}
|
||||
|
||||
IMoveAction::IMoveAction(std::istream &is)
|
||||
{
|
||||
std::string ts;
|
||||
|
||||
std::getline(is, ts, ' ');
|
||||
count = stoi(ts);
|
||||
|
||||
std::getline(is, from_inv, ' ');
|
||||
|
||||
std::getline(is, from_list, ' ');
|
||||
|
||||
std::getline(is, ts, ' ');
|
||||
from_i = stoi(ts);
|
||||
|
||||
std::getline(is, to_inv, ' ');
|
||||
|
||||
std::getline(is, to_list, ' ');
|
||||
|
||||
std::getline(is, ts, ' ');
|
||||
to_i = stoi(ts);
|
||||
}
|
||||
|
||||
void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
|
||||
ServerEnvironment *env)
|
||||
{
|
||||
Inventory *inv_from = mgr->getInventory(c, from_inv);
|
||||
Inventory *inv_to = mgr->getInventory(c, to_inv);
|
||||
|
||||
if(!inv_from){
|
||||
infostream<<"IMoveAction::apply(): FAIL: source inventory not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", to_inv=\""<<to_inv<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
if(!inv_to){
|
||||
infostream<<"IMoveAction::apply(): FAIL: destination inventory not found: "
|
||||
"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", to_inv=\""<<to_inv<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryList *list_from = inv_from->getList(from_list);
|
||||
InventoryList *list_to = inv_to->getList(to_list);
|
||||
|
||||
/*
|
||||
If a list doesn't exist or the source item doesn't exist
|
||||
*/
|
||||
if(!list_from){
|
||||
infostream<<"IMoveAction::apply(): FAIL: source list not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", from_list=\""<<from_list<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
if(!list_to){
|
||||
infostream<<"IMoveAction::apply(): FAIL: destination list not found: "
|
||||
<<"context=["<<describeC(c)<<"], to_inv=\""<<to_inv<<"\""
|
||||
<<", to_list=\""<<to_list<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
if(list_from->getItem(from_i) == NULL)
|
||||
{
|
||||
infostream<<"IMoveAction::apply(): FAIL: source item not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", from_list=\""<<from_list<<"\""
|
||||
<<" from_i="<<from_i<<std::endl;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
If the source and the destination slots are the same
|
||||
*/
|
||||
if(inv_from == inv_to && list_from == list_to && from_i == to_i)
|
||||
{
|
||||
infostream<<"IMoveAction::apply(): FAIL: source and destination slots "
|
||||
<<"are the same: inv=\""<<from_inv<<"\" list=\""<<from_list
|
||||
<<"\" i="<<from_i<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Take item from source list
|
||||
InventoryItem *item1 = NULL;
|
||||
if(count == 0)
|
||||
item1 = list_from->changeItem(from_i, NULL);
|
||||
else
|
||||
item1 = list_from->takeItem(from_i, count);
|
||||
|
||||
// Try to add the item to destination list
|
||||
InventoryItem *olditem = item1;
|
||||
item1 = list_to->addItem(to_i, item1);
|
||||
|
||||
// If something is returned, the item was not fully added
|
||||
if(item1 != NULL)
|
||||
{
|
||||
// If olditem is returned, nothing was added.
|
||||
bool nothing_added = (item1 == olditem);
|
||||
|
||||
// If something else is returned, part of the item was left unadded.
|
||||
// Add the other part back to the source item
|
||||
list_from->addItem(from_i, item1);
|
||||
|
||||
// If olditem is returned, nothing was added.
|
||||
// Swap the items
|
||||
if(nothing_added)
|
||||
{
|
||||
// Take item from source list
|
||||
item1 = list_from->changeItem(from_i, NULL);
|
||||
// Adding was not possible, swap the items.
|
||||
InventoryItem *item2 = list_to->changeItem(to_i, item1);
|
||||
// Put item from destination list to the source list
|
||||
list_from->changeItem(from_i, item2);
|
||||
}
|
||||
}
|
||||
|
||||
mgr->inventoryModified(c, from_inv);
|
||||
if(from_inv != to_inv)
|
||||
mgr->inventoryModified(c, to_inv);
|
||||
|
||||
infostream<<"IMoveAction::apply(): moved at "
|
||||
<<"["<<describeC(c)<<"]"
|
||||
<<" from inv=\""<<from_inv<<"\""
|
||||
<<" list=\""<<from_list<<"\""
|
||||
<<" i="<<from_i
|
||||
<<" to inv=\""<<to_inv<<"\""
|
||||
<<" list=\""<<to_list<<"\""
|
||||
<<" i="<<to_i
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
IDropAction::IDropAction(std::istream &is)
|
||||
{
|
||||
std::string ts;
|
||||
|
||||
std::getline(is, ts, ' ');
|
||||
count = stoi(ts);
|
||||
|
||||
std::getline(is, from_inv, ' ');
|
||||
|
||||
std::getline(is, from_list, ' ');
|
||||
|
||||
std::getline(is, ts, ' ');
|
||||
from_i = stoi(ts);
|
||||
}
|
||||
|
||||
void IDropAction::apply(InventoryContext *c, InventoryManager *mgr,
|
||||
ServerEnvironment *env)
|
||||
{
|
||||
if(c->current_player == NULL){
|
||||
infostream<<"IDropAction::apply(): FAIL: current_player is NULL"<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do NOT cast directly to ServerActiveObject*, it breaks
|
||||
// because of multiple inheritance.
|
||||
ServerActiveObject *dropper =
|
||||
static_cast<ServerActiveObject*>(
|
||||
static_cast<ServerRemotePlayer*>(
|
||||
c->current_player
|
||||
));
|
||||
|
||||
Inventory *inv_from = mgr->getInventory(c, from_inv);
|
||||
|
||||
if(!inv_from){
|
||||
infostream<<"IDropAction::apply(): FAIL: source inventory not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryList *list_from = inv_from->getList(from_list);
|
||||
|
||||
/*
|
||||
If a list doesn't exist or the source item doesn't exist
|
||||
*/
|
||||
if(!list_from){
|
||||
infostream<<"IDropAction::apply(): FAIL: source list not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", from_list=\""<<from_list<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
InventoryItem *item = list_from->getItem(from_i);
|
||||
if(item == NULL)
|
||||
{
|
||||
infostream<<"IDropAction::apply(): FAIL: source item not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", from_list=\""<<from_list<<"\""
|
||||
<<" from_i="<<from_i<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
v3f pos = dropper->getBasePosition();
|
||||
pos.Y += 0.5*BS;
|
||||
|
||||
s16 count2 = count;
|
||||
if(count2 == 0)
|
||||
count2 = -1;
|
||||
|
||||
/*
|
||||
Drop the item
|
||||
*/
|
||||
bool remove = item->dropOrPlace(env, dropper, pos, false, count2);
|
||||
if(remove)
|
||||
list_from->deleteItem(from_i);
|
||||
|
||||
mgr->inventoryModified(c, from_inv);
|
||||
|
||||
infostream<<"IDropAction::apply(): dropped "
|
||||
<<"["<<describeC(c)<<"]"
|
||||
<<" from inv=\""<<from_inv<<"\""
|
||||
<<" list=\""<<from_list<<"\""
|
||||
<<" i="<<from_i
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
/*
|
||||
Craft checking system
|
||||
*/
|
||||
|
||||
bool ItemSpec::checkItem(const InventoryItem *item) const
|
||||
{
|
||||
if(type == ITEM_NONE)
|
||||
{
|
||||
// Has to be no item
|
||||
if(item != NULL)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// There should be an item
|
||||
if(item == NULL)
|
||||
return false;
|
||||
|
||||
std::string itemname = item->getName();
|
||||
|
||||
if(type == ITEM_MATERIAL)
|
||||
{
|
||||
if(itemname != "MaterialItem")
|
||||
return false;
|
||||
MaterialItem *mitem = (MaterialItem*)item;
|
||||
if(num != 65535){
|
||||
if(mitem->getMaterial() != num)
|
||||
return false;
|
||||
} else {
|
||||
if(mitem->getNodeName() != name)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(type == ITEM_CRAFT)
|
||||
{
|
||||
if(itemname != "CraftItem")
|
||||
return false;
|
||||
CraftItem *mitem = (CraftItem*)item;
|
||||
if(mitem->getSubName() != name)
|
||||
return false;
|
||||
}
|
||||
else if(type == ITEM_TOOL)
|
||||
{
|
||||
// Not supported yet
|
||||
assert(0);
|
||||
}
|
||||
else if(type == ITEM_MBO)
|
||||
{
|
||||
// Not supported yet
|
||||
assert(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not supported yet
|
||||
assert(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkItemCombination(InventoryItem const * const *items, const ItemSpec *specs)
|
||||
{
|
||||
u16 items_min_x = 100;
|
||||
u16 items_max_x = 100;
|
||||
u16 items_min_y = 100;
|
||||
u16 items_max_y = 100;
|
||||
for(u16 y=0; y<3; y++)
|
||||
for(u16 x=0; x<3; x++)
|
||||
{
|
||||
if(items[y*3 + x] == NULL)
|
||||
continue;
|
||||
if(items_min_x == 100 || x < items_min_x)
|
||||
items_min_x = x;
|
||||
if(items_min_y == 100 || y < items_min_y)
|
||||
items_min_y = y;
|
||||
if(items_max_x == 100 || x > items_max_x)
|
||||
items_max_x = x;
|
||||
if(items_max_y == 100 || y > items_max_y)
|
||||
items_max_y = y;
|
||||
}
|
||||
// No items at all, just return false
|
||||
if(items_min_x == 100)
|
||||
return false;
|
||||
|
||||
u16 items_w = items_max_x - items_min_x + 1;
|
||||
u16 items_h = items_max_y - items_min_y + 1;
|
||||
|
||||
u16 specs_min_x = 100;
|
||||
u16 specs_max_x = 100;
|
||||
u16 specs_min_y = 100;
|
||||
u16 specs_max_y = 100;
|
||||
for(u16 y=0; y<3; y++)
|
||||
for(u16 x=0; x<3; x++)
|
||||
{
|
||||
if(specs[y*3 + x].type == ITEM_NONE)
|
||||
continue;
|
||||
if(specs_min_x == 100 || x < specs_min_x)
|
||||
specs_min_x = x;
|
||||
if(specs_min_y == 100 || y < specs_min_y)
|
||||
specs_min_y = y;
|
||||
if(specs_max_x == 100 || x > specs_max_x)
|
||||
specs_max_x = x;
|
||||
if(specs_max_y == 100 || y > specs_max_y)
|
||||
specs_max_y = y;
|
||||
}
|
||||
// No specs at all, just return false
|
||||
if(specs_min_x == 100)
|
||||
return false;
|
||||
|
||||
u16 specs_w = specs_max_x - specs_min_x + 1;
|
||||
u16 specs_h = specs_max_y - specs_min_y + 1;
|
||||
|
||||
// Different sizes
|
||||
if(items_w != specs_w || items_h != specs_h)
|
||||
return false;
|
||||
|
||||
for(u16 y=0; y<specs_h; y++)
|
||||
for(u16 x=0; x<specs_w; x++)
|
||||
{
|
||||
u16 items_x = items_min_x + x;
|
||||
u16 items_y = items_min_y + y;
|
||||
u16 specs_x = specs_min_x + x;
|
||||
u16 specs_y = specs_min_y + y;
|
||||
const InventoryItem *item = items[items_y * 3 + items_x];
|
||||
const ItemSpec &spec = specs[specs_y * 3 + specs_x];
|
||||
|
||||
if(spec.checkItem(item) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkItemCombination(const InventoryItem * const * items,
|
||||
const InventoryItem * const * specs)
|
||||
{
|
||||
u16 items_min_x = 100;
|
||||
u16 items_max_x = 100;
|
||||
u16 items_min_y = 100;
|
||||
u16 items_max_y = 100;
|
||||
for(u16 y=0; y<3; y++)
|
||||
for(u16 x=0; x<3; x++)
|
||||
{
|
||||
if(items[y*3 + x] == NULL)
|
||||
continue;
|
||||
if(items_min_x == 100 || x < items_min_x)
|
||||
items_min_x = x;
|
||||
if(items_min_y == 100 || y < items_min_y)
|
||||
items_min_y = y;
|
||||
if(items_max_x == 100 || x > items_max_x)
|
||||
items_max_x = x;
|
||||
if(items_max_y == 100 || y > items_max_y)
|
||||
items_max_y = y;
|
||||
}
|
||||
// No items at all, just return false
|
||||
if(items_min_x == 100)
|
||||
return false;
|
||||
|
||||
u16 items_w = items_max_x - items_min_x + 1;
|
||||
u16 items_h = items_max_y - items_min_y + 1;
|
||||
|
||||
u16 specs_min_x = 100;
|
||||
u16 specs_max_x = 100;
|
||||
u16 specs_min_y = 100;
|
||||
u16 specs_max_y = 100;
|
||||
for(u16 y=0; y<3; y++)
|
||||
for(u16 x=0; x<3; x++)
|
||||
{
|
||||
if(specs[y*3 + x] == NULL)
|
||||
continue;
|
||||
if(specs_min_x == 100 || x < specs_min_x)
|
||||
specs_min_x = x;
|
||||
if(specs_min_y == 100 || y < specs_min_y)
|
||||
specs_min_y = y;
|
||||
if(specs_max_x == 100 || x > specs_max_x)
|
||||
specs_max_x = x;
|
||||
if(specs_max_y == 100 || y > specs_max_y)
|
||||
specs_max_y = y;
|
||||
}
|
||||
// No specs at all, just return false
|
||||
if(specs_min_x == 100)
|
||||
return false;
|
||||
|
||||
u16 specs_w = specs_max_x - specs_min_x + 1;
|
||||
u16 specs_h = specs_max_y - specs_min_y + 1;
|
||||
|
||||
// Different sizes
|
||||
if(items_w != specs_w || items_h != specs_h)
|
||||
return false;
|
||||
|
||||
for(u16 y=0; y<specs_h; y++)
|
||||
for(u16 x=0; x<specs_w; x++)
|
||||
{
|
||||
u16 items_x = items_min_x + x;
|
||||
u16 items_y = items_min_y + y;
|
||||
u16 specs_x = specs_min_x + x;
|
||||
u16 specs_y = specs_min_y + y;
|
||||
const InventoryItem *item = items[items_y * 3 + items_x];
|
||||
const InventoryItem *spec = specs[specs_y * 3 + specs_x];
|
||||
|
||||
if(item == NULL && spec == NULL)
|
||||
continue;
|
||||
if(item == NULL && spec != NULL)
|
||||
return false;
|
||||
if(item != NULL && spec == NULL)
|
||||
return false;
|
||||
if(!spec->isSubsetOf(item))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
228
src/inventorymanager.h
Normal file
228
src/inventorymanager.h
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
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 INVENTORYMANAGER_HEADER
|
||||
#define INVENTORYMANAGER_HEADER
|
||||
|
||||
#include "inventory.h"
|
||||
|
||||
// Should probably somehow replace InventoryContext over time
|
||||
struct InventoryLocation
|
||||
{
|
||||
enum Type{
|
||||
UNDEFINED,
|
||||
PLAYER,
|
||||
NODEMETA
|
||||
} type;
|
||||
|
||||
std::string name; // PLAYER
|
||||
v3s16 p; // NODEMETA
|
||||
|
||||
void setPlayer(const std::string &name_)
|
||||
{
|
||||
type = PLAYER;
|
||||
name = name_;
|
||||
}
|
||||
void setNodeMeta(v3s16 p_)
|
||||
{
|
||||
type = NODEMETA;
|
||||
p = p_;
|
||||
}
|
||||
};
|
||||
|
||||
class Player;
|
||||
|
||||
struct InventoryContext
|
||||
{
|
||||
Player *current_player;
|
||||
|
||||
InventoryContext():
|
||||
current_player(NULL)
|
||||
{}
|
||||
};
|
||||
|
||||
struct InventoryAction;
|
||||
|
||||
class InventoryManager
|
||||
{
|
||||
public:
|
||||
InventoryManager(){}
|
||||
virtual ~InventoryManager(){}
|
||||
|
||||
// Get an inventory or set it modified (so it will be updated over
|
||||
// network or so)
|
||||
virtual Inventory* getInventory(const InventoryLocation &loc){return NULL;}
|
||||
virtual void setInventoryModified(const InventoryLocation &loc){}
|
||||
|
||||
// Used on the client to send an action to the server
|
||||
virtual void inventoryAction(InventoryAction *a){}
|
||||
|
||||
// (Deprecated; these wrap to the latter ones)
|
||||
// Get a pointer to an inventory specified by id. id can be:
|
||||
// - "current_player"
|
||||
// - "nodemeta:X,Y,Z"
|
||||
Inventory* getInventory(InventoryContext *c, std::string id);
|
||||
// Used on the server by InventoryAction::apply and other stuff
|
||||
void inventoryModified(InventoryContext *c, std::string id);
|
||||
};
|
||||
|
||||
#define IACTION_MOVE 0
|
||||
#define IACTION_DROP 1
|
||||
|
||||
struct InventoryAction
|
||||
{
|
||||
static InventoryAction * deSerialize(std::istream &is);
|
||||
|
||||
virtual u16 getType() const = 0;
|
||||
virtual void serialize(std::ostream &os) const = 0;
|
||||
virtual void apply(InventoryContext *c, InventoryManager *mgr,
|
||||
ServerEnvironment *env) = 0;
|
||||
};
|
||||
|
||||
struct IMoveAction : public InventoryAction
|
||||
{
|
||||
// count=0 means "everything"
|
||||
u16 count;
|
||||
std::string from_inv;
|
||||
std::string from_list;
|
||||
s16 from_i;
|
||||
std::string to_inv;
|
||||
std::string to_list;
|
||||
s16 to_i;
|
||||
|
||||
IMoveAction()
|
||||
{
|
||||
count = 0;
|
||||
from_i = -1;
|
||||
to_i = -1;
|
||||
}
|
||||
|
||||
IMoveAction(std::istream &is);
|
||||
|
||||
u16 getType() const
|
||||
{
|
||||
return IACTION_MOVE;
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os) const
|
||||
{
|
||||
os<<"Move ";
|
||||
os<<count<<" ";
|
||||
os<<from_inv<<" ";
|
||||
os<<from_list<<" ";
|
||||
os<<from_i<<" ";
|
||||
os<<to_inv<<" ";
|
||||
os<<to_list<<" ";
|
||||
os<<to_i;
|
||||
}
|
||||
|
||||
void apply(InventoryContext *c, InventoryManager *mgr,
|
||||
ServerEnvironment *env);
|
||||
};
|
||||
|
||||
struct IDropAction : public InventoryAction
|
||||
{
|
||||
// count=0 means "everything"
|
||||
u16 count;
|
||||
std::string from_inv;
|
||||
std::string from_list;
|
||||
s16 from_i;
|
||||
|
||||
IDropAction()
|
||||
{
|
||||
count = 0;
|
||||
from_i = -1;
|
||||
}
|
||||
|
||||
IDropAction(std::istream &is);
|
||||
|
||||
u16 getType() const
|
||||
{
|
||||
return IACTION_DROP;
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os) const
|
||||
{
|
||||
os<<"Drop ";
|
||||
os<<count<<" ";
|
||||
os<<from_inv<<" ";
|
||||
os<<from_list<<" ";
|
||||
os<<from_i;
|
||||
}
|
||||
|
||||
void apply(InventoryContext *c, InventoryManager *mgr,
|
||||
ServerEnvironment *env);
|
||||
};
|
||||
|
||||
/*
|
||||
Craft checking system
|
||||
*/
|
||||
|
||||
enum ItemSpecType
|
||||
{
|
||||
ITEM_NONE,
|
||||
ITEM_MATERIAL,
|
||||
ITEM_CRAFT,
|
||||
ITEM_TOOL,
|
||||
ITEM_MBO
|
||||
};
|
||||
|
||||
struct ItemSpec
|
||||
{
|
||||
enum ItemSpecType type;
|
||||
// Only other one of these is used
|
||||
std::string name;
|
||||
u16 num;
|
||||
|
||||
ItemSpec():
|
||||
type(ITEM_NONE)
|
||||
{
|
||||
}
|
||||
ItemSpec(enum ItemSpecType a_type, std::string a_name):
|
||||
type(a_type),
|
||||
name(a_name),
|
||||
num(65535)
|
||||
{
|
||||
}
|
||||
ItemSpec(enum ItemSpecType a_type, u16 a_num):
|
||||
type(a_type),
|
||||
name(""),
|
||||
num(a_num)
|
||||
{
|
||||
}
|
||||
|
||||
bool checkItem(const InventoryItem *item) const;
|
||||
};
|
||||
|
||||
/*
|
||||
items: a pointer to an array of 9 pointers to items
|
||||
specs: a pointer to an array of 9 ItemSpecs
|
||||
*/
|
||||
bool checkItemCombination(const InventoryItem * const*items, const ItemSpec *specs);
|
||||
|
||||
/*
|
||||
items: a pointer to an array of 9 pointers to items
|
||||
specs: a pointer to an array of 9 pointers to items
|
||||
*/
|
||||
bool checkItemCombination(const InventoryItem * const * items,
|
||||
const InventoryItem * const * specs);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -181,13 +181,13 @@ irr::EKEY_CODE keyname_to_keycode(const char *name)
|
||||
}
|
||||
|
||||
static const char *KeyNames[] =
|
||||
{ "-", "KEY_LBUTTON", "KEY_RBUTTON", "Cancel", "Middle Button", "X Button 1",
|
||||
"X Button 2", "-", "Back", "Tab", "-", "-", "Clear", "Return", "-",
|
||||
"-", "KEY_SHIFT", "Control", "Menu", "Pause", "Capital", "Kana", "-",
|
||||
"Junja", "Final", "Kanji", "-", "Escape", "Convert", "Nonconvert",
|
||||
"Accept", "Mode Change", "KEY_SPACE", "Priot", "Next", "KEY_END",
|
||||
"KEY_HOME", "Left", "Up", "Right", "Down", "Select", "KEY_PRINT",
|
||||
"Execute", "Snapshot", "Insert", "Delete", "Help", "KEY_KEY_0",
|
||||
{ "-", "KEY_LBUTTON", "KEY_RBUTTON", "KEY_CANCEL", "KEY_MBUTTON", "KEY_XBUTTON1",
|
||||
"KEY_XBUTTON2", "-", "KEY_BACK", "KEY_TAB", "-", "-", "KEY_CLEAR", "KEY_RETURN", "-",
|
||||
"-", "KEY_SHIFT", "KEY_CONTROL", "KEY_MENU", "KEY_PAUSE", "KEY_CAPITAL", "KEY_KANA", "-",
|
||||
"KEY_JUNJA", "KEY_FINAL", "KEY_KANJI", "-", "KEY_ESCAPE", "KEY_CONVERT", "KEY_NONCONVERT",
|
||||
"KEY_ACCEPT", "KEY_MODECHANGE", "KEY_SPACE", "KEY_PRIOR", "KEY_NEXT", "KEY_END",
|
||||
"KEY_HOME", "KEY_LEFT", "KEY_UP", "KEY_RIGHT", "KEY_DOWN", "KEY_SELECT", "KEY_PRINT",
|
||||
"KEY_EXECUTE", "KEY_SNAPSHOT", "KEY_INSERT", "KEY_DELETE", "KEY_HELP", "KEY_KEY_0",
|
||||
"KEY_KEY_1", "KEY_KEY_2", "KEY_KEY_3", "KEY_KEY_4", "KEY_KEY_5",
|
||||
"KEY_KEY_6", "KEY_KEY_7", "KEY_KEY_8", "KEY_KEY_9", "-", "-", "-", "-",
|
||||
"-", "-", "-", "KEY_KEY_A", "KEY_KEY_B", "KEY_KEY_C", "KEY_KEY_D",
|
||||
@@ -195,25 +195,25 @@ static const char *KeyNames[] =
|
||||
"KEY_KEY_J", "KEY_KEY_K", "KEY_KEY_L", "KEY_KEY_M", "KEY_KEY_N",
|
||||
"KEY_KEY_O", "KEY_KEY_P", "KEY_KEY_Q", "KEY_KEY_R", "KEY_KEY_S",
|
||||
"KEY_KEY_T", "KEY_KEY_U", "KEY_KEY_V", "KEY_KEY_W", "KEY_KEY_X",
|
||||
"KEY_KEY_Y", "KEY_KEY_Z", "Left Windows", "Right Windows", "Apps", "-",
|
||||
"Sleep", "KEY_NUMPAD0", "KEY_NUMPAD1", "KEY_NUMPAD2", "KEY_NUMPAD3",
|
||||
"KEY_KEY_Y", "KEY_KEY_Z", "KEY_LWIN", "KEY_RWIN", "KEY_APPS", "-",
|
||||
"KEY_SLEEP", "KEY_NUMPAD0", "KEY_NUMPAD1", "KEY_NUMPAD2", "KEY_NUMPAD3",
|
||||
"KEY_NUMPAD4", "KEY_NUMPAD5", "KEY_NUMPAD6", "KEY_NUMPAD7",
|
||||
"KEY_NUMPAD8", "KEY_NUMPAD9", "Numpad *", "Numpad +", "Numpad /",
|
||||
"Numpad -", "Numpad .", "Numpad /", "KEY_F1", "KEY_F2", "KEY_F3",
|
||||
"KEY_NUMPAD8", "KEY_NUMPAD9", "KEY_MULTIPLY", "KEY_ADD", "KEY_SEPERATOR",
|
||||
"KEY_SUBTRACT", "KEY_DECIMAL", "KEY_DIVIDE", "KEY_F1", "KEY_F2", "KEY_F3",
|
||||
"KEY_F4", "KEY_F5", "KEY_F6", "KEY_F7", "KEY_F8", "KEY_F9", "KEY_F10",
|
||||
"KEY_F11", "KEY_F12", "KEY_F13", "KEY_F14", "KEY_F15", "KEY_F16",
|
||||
"KEY_F17", "KEY_F18", "KEY_F19", "KEY_F20", "KEY_F21", "KEY_F22",
|
||||
"KEY_F23", "KEY_F24", "-", "-", "-", "-", "-", "-", "-", "-",
|
||||
"Num Lock", "Scroll Lock", "-", "-", "-", "-", "-", "-", "-", "-", "-",
|
||||
"-", "-", "-", "-", "-", "KEY_LSHIFT", "KEY_RSHIFT", "Left Control",
|
||||
"Right Control", "Left Menu", "Right Menu", "-", "-", "-", "-", "-",
|
||||
"KEY_NUMLOCK", "KEY_SCROLL", "-", "-", "-", "-", "-", "-", "-", "-", "-",
|
||||
"-", "-", "-", "-", "-", "KEY_LSHIFT", "KEY_RSHIFT", "KEY_LCONTROL",
|
||||
"KEY_RCONTROL", "KEY_LMENU", "KEY_RMENU", "-", "-", "-", "-", "-",
|
||||
"-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-",
|
||||
"-", "-", "Plus", "Comma", "Minus", "Period", "-", "-", "-", "-", "-",
|
||||
"-", "-", "KEY_PLUS", "KEY_COMMA", "KEY_MINUS", "KEY_PERIOD", "-", "-", "-", "-", "-",
|
||||
"-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-",
|
||||
"-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-",
|
||||
"-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-",
|
||||
"-", "-", "-", "-", "-", "-", "-", "-", "Attn", "CrSel", "ExSel",
|
||||
"Erase OEF", "Play", "Zoom", "PA1", "OEM Clear", "-" };
|
||||
"-", "-", "-", "-", "-", "-", "-", "-", "KEY_ATTN", "KEY_CRSEL", "KEY_EXSEL",
|
||||
"KEY_EREOF", "KEY_PLAY", "KEY_ZOOM", "KEY_PA1", "KEY_OEM_CLEAR", "-" };
|
||||
|
||||
#define N_(text) text
|
||||
|
||||
|
||||
@@ -104,9 +104,9 @@ HittingProperties getHittingProperties(const MaterialProperties *mp,
|
||||
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;
|
||||
s16 hp = 2.0 * 2.0 / digprop.time;
|
||||
// Wear is the same as for digging a single node
|
||||
s16 wear = (float)digprop.wear + 0.5;
|
||||
s16 wear = (float)digprop.wear;
|
||||
|
||||
return HittingProperties(hp, wear);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MODS_HEADER
|
||||
#define MODS_HEADER
|
||||
|
||||
#include "irrlichttypes.h"
|
||||
#include <set>
|
||||
#include <string>
|
||||
@@ -59,3 +62,5 @@ struct ModSpec
|
||||
core::list<ModSpec> getMods(core::list<std::string> &modspaths)
|
||||
throw(ModError);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -403,15 +403,8 @@ class CNodeDefManager: public IWritableNodeDefManager
|
||||
}
|
||||
virtual bool getId(const std::string &name_, content_t &result) const
|
||||
{
|
||||
std::string name = name_;
|
||||
// Convert name according to possible alias
|
||||
std::map<std::string, std::string>::const_iterator i;
|
||||
i = m_aliases.find(name);
|
||||
if(i != m_aliases.end()){
|
||||
/*infostream<<"ndef: alias active: "<<name<<" -> "<<i->second
|
||||
<<std::endl;*/
|
||||
name = i->second;
|
||||
}
|
||||
std::string name = getAlias(name_);
|
||||
// Get id
|
||||
return m_name_id_mapping.getId(name, result);
|
||||
}
|
||||
@@ -427,6 +420,14 @@ class CNodeDefManager: public IWritableNodeDefManager
|
||||
getId(name, id);
|
||||
return get(id);
|
||||
}
|
||||
virtual std::string getAlias(const std::string &name) const
|
||||
{
|
||||
std::map<std::string, std::string>::const_iterator i;
|
||||
i = m_aliases.find(name);
|
||||
if(i != m_aliases.end())
|
||||
return i->second;
|
||||
return name;
|
||||
}
|
||||
// IWritableNodeDefManager
|
||||
virtual void set(content_t c, const ContentFeatures &def)
|
||||
{
|
||||
|
||||
@@ -253,6 +253,7 @@ class INodeDefManager
|
||||
virtual bool getId(const std::string &name, content_t &result) const=0;
|
||||
virtual content_t getId(const std::string &name) const=0;
|
||||
virtual const ContentFeatures& get(const std::string &name) const=0;
|
||||
virtual std::string getAlias(const std::string &name) const =0;
|
||||
|
||||
virtual void serialize(std::ostream &os)=0;
|
||||
};
|
||||
@@ -270,6 +271,7 @@ class IWritableNodeDefManager : public INodeDefManager
|
||||
virtual content_t getId(const std::string &name) const=0;
|
||||
// If not found, returns the features of CONTENT_IGNORE
|
||||
virtual const ContentFeatures& get(const std::string &name) const=0;
|
||||
virtual std::string getAlias(const std::string &name) const =0;
|
||||
|
||||
// Register node definition
|
||||
virtual void set(content_t c, const ContentFeatures &def)=0;
|
||||
|
||||
10
src/player.h
10
src/player.h
@@ -102,6 +102,16 @@ class Player
|
||||
return m_yaw;
|
||||
}
|
||||
|
||||
f32 getRadPitch()
|
||||
{
|
||||
return -1.0 * m_pitch * core::DEGTORAD;
|
||||
}
|
||||
|
||||
f32 getRadYaw()
|
||||
{
|
||||
return (m_yaw + 90.) * core::DEGTORAD;
|
||||
}
|
||||
|
||||
virtual void updateName(const char *name)
|
||||
{
|
||||
snprintf(m_name, PLAYERNAME_SIZE, "%s", name);
|
||||
|
||||
@@ -35,13 +35,19 @@ LuaError::LuaError(lua_State *L, const std::string &s)
|
||||
{
|
||||
m_s = "LuaError: ";
|
||||
m_s += s + "\n";
|
||||
m_s += script_get_backtrace(L);
|
||||
}
|
||||
|
||||
std::string script_get_backtrace(lua_State *L)
|
||||
{
|
||||
std::string s;
|
||||
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);
|
||||
s += lua_tostring(L, -1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
@@ -50,6 +56,7 @@ LuaError::LuaError(lua_State *L, const std::string &s)
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return s;
|
||||
}
|
||||
|
||||
void script_error(lua_State *L, const char *fmt, ...)
|
||||
@@ -94,8 +101,10 @@ bool script_load(lua_State *L, const char *path)
|
||||
errorstream<<"[LUA] "<<lua_tostring(L, -1)<<std::endl;
|
||||
errorstream<<"[LUA] "<<std::endl;
|
||||
lua_pop(L, 1); // Pop error message from stack
|
||||
lua_pop(L, 1); // Pop the error handler from stack
|
||||
return false;
|
||||
}
|
||||
lua_pop(L, 1); // Pop the error handler from stack
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ class LuaError : public std::exception
|
||||
|
||||
lua_State* script_init();
|
||||
void script_deinit(lua_State *L);
|
||||
std::string script_get_backtrace(lua_State *L);
|
||||
void script_error(lua_State *L, const char *fmt, ...);
|
||||
bool script_load(lua_State *L, const char *path);
|
||||
|
||||
|
||||
3457
src/scriptapi.cpp
3457
src/scriptapi.cpp
File diff suppressed because it is too large
Load Diff
@@ -62,6 +62,7 @@ void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp);
|
||||
|
||||
/* misc */
|
||||
void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player);
|
||||
void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player);
|
||||
bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player);
|
||||
void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player);
|
||||
|
||||
|
||||
488
src/server.cpp
488
src/server.cpp
@@ -48,6 +48,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "mapgen.h"
|
||||
#include "content_abm.h"
|
||||
#include "mods.h"
|
||||
#include "sha1.h"
|
||||
#include "base64.h"
|
||||
|
||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||
|
||||
@@ -249,7 +251,7 @@ void * EmergeThread::Thread()
|
||||
t.stop(true); // Hide output
|
||||
}
|
||||
|
||||
{
|
||||
do{ // enable break
|
||||
// Lock environment again to access the map
|
||||
JMutexAutoLock envlock(m_server->m_env_mutex);
|
||||
|
||||
@@ -262,6 +264,11 @@ void * EmergeThread::Thread()
|
||||
|
||||
// Get central block
|
||||
block = map.getBlockNoCreateNoEx(p);
|
||||
|
||||
// If block doesn't exist, don't try doing anything with it
|
||||
// This happens if the block is not in generation boundaries
|
||||
if(!block)
|
||||
break;
|
||||
|
||||
/*
|
||||
Do some post-generate stuff
|
||||
@@ -285,7 +292,7 @@ void * EmergeThread::Thread()
|
||||
|
||||
// Activate objects and stuff
|
||||
m_server->m_env->activateBlock(block, 0);
|
||||
}
|
||||
}while(false);
|
||||
}
|
||||
|
||||
if(block == NULL)
|
||||
@@ -910,10 +917,10 @@ Server::Server(
|
||||
throw ModError("Failed to load and run "+builtinpath);
|
||||
}
|
||||
// Load and run "mod" scripts
|
||||
core::list<ModSpec> mods = getMods(m_modspaths);
|
||||
for(core::list<ModSpec>::Iterator i = mods.begin();
|
||||
i != mods.end(); i++){
|
||||
ModSpec mod = *i;
|
||||
m_mods = getMods(m_modspaths);
|
||||
for(core::list<ModSpec>::Iterator i = m_mods.begin();
|
||||
i != m_mods.end(); i++){
|
||||
const ModSpec &mod = *i;
|
||||
infostream<<"Server: Loading mod \""<<mod.name<<"\""<<std::endl;
|
||||
std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
|
||||
bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
|
||||
@@ -924,6 +931,9 @@ Server::Server(
|
||||
}
|
||||
}
|
||||
|
||||
// Read Textures and calculate sha1 sums
|
||||
PrepareTextures();
|
||||
|
||||
// Initialize Environment
|
||||
|
||||
m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua,
|
||||
@@ -2105,8 +2115,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
// Send CraftItem definitions
|
||||
SendCraftItemDef(m_con, peer_id, m_craftitemdef);
|
||||
|
||||
// Send textures
|
||||
SendTextures(peer_id);
|
||||
// Send texture announcement
|
||||
SendTextureAnnouncement(peer_id);
|
||||
|
||||
// Send player info to all players
|
||||
//SendPlayerInfos();
|
||||
@@ -2130,9 +2140,6 @@ 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());
|
||||
|
||||
@@ -2453,7 +2460,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
craftresult and immediately moved to the free slot.
|
||||
*/
|
||||
do{
|
||||
Inventory *inv_to = getInventory(&c, ma->to_inv);
|
||||
Inventory *inv_to = InventoryManager::getInventory(&c, ma->to_inv);
|
||||
if(!inv_to) break;
|
||||
InventoryList *list_to = inv_to->getList(ma->to_list);
|
||||
if(!list_to) break;
|
||||
@@ -2820,6 +2827,30 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
// ActiveObject is added to environment in AsyncRunStep after
|
||||
// the previous addition has been succesfully removed
|
||||
}
|
||||
else if(command == TOSERVER_REQUEST_TEXTURES) {
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is(datastring, std::ios_base::binary);
|
||||
|
||||
infostream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
|
||||
|
||||
core::list<TextureRequest> tosend;
|
||||
|
||||
u16 numtextures = readU16(is);
|
||||
|
||||
for(int i = 0; i < numtextures; i++) {
|
||||
|
||||
std::string name = deSerializeString(is);
|
||||
|
||||
tosend.push_back(TextureRequest(name));
|
||||
infostream<<"TOSERVER_REQUEST_TEXTURES: requested texture " << name <<std::endl;
|
||||
}
|
||||
|
||||
SendTexturesRequested(peer_id, tosend);
|
||||
|
||||
// Now the client should know about everything
|
||||
// (definitions and textures)
|
||||
getClient(peer_id)->definitions_sent = true;
|
||||
}
|
||||
else if(command == TOSERVER_INTERACT)
|
||||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
@@ -2964,7 +2995,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
<<pointed.object_id<<std::endl;
|
||||
|
||||
// Do stuff
|
||||
pointed_object->punch(srp);
|
||||
pointed_object->punch(srp, srp->m_time_from_last_punch);
|
||||
srp->m_time_from_last_punch = 0;
|
||||
}
|
||||
|
||||
} // action == 0
|
||||
@@ -3140,12 +3172,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
}
|
||||
|
||||
item = NULL;
|
||||
|
||||
if(mineral != MINERAL_NONE)
|
||||
item = getDiggedMineralItem(mineral, this);
|
||||
|
||||
// If not mineral
|
||||
if(item == NULL)
|
||||
|
||||
{
|
||||
const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item;
|
||||
s32 extra_rarity = m_nodedef->get(material).extra_dug_item_rarity;
|
||||
@@ -3516,6 +3543,68 @@ void Server::onMapEditEvent(MapEditEvent *event)
|
||||
m_unsent_map_edit_queue.push_back(e);
|
||||
}
|
||||
|
||||
Inventory* Server::getInventory(const InventoryLocation &loc)
|
||||
{
|
||||
switch(loc.type){
|
||||
case InventoryLocation::UNDEFINED:
|
||||
{}
|
||||
break;
|
||||
case InventoryLocation::PLAYER:
|
||||
{
|
||||
Player *player = m_env->getPlayer(loc.name.c_str());
|
||||
if(!player)
|
||||
return NULL;
|
||||
return &player->inventory;
|
||||
}
|
||||
break;
|
||||
case InventoryLocation::NODEMETA:
|
||||
{
|
||||
NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
|
||||
if(!meta)
|
||||
return NULL;
|
||||
return meta->getInventory();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void Server::setInventoryModified(const InventoryLocation &loc)
|
||||
{
|
||||
switch(loc.type){
|
||||
case InventoryLocation::UNDEFINED:
|
||||
{}
|
||||
break;
|
||||
case InventoryLocation::PLAYER:
|
||||
{
|
||||
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
|
||||
(m_env->getPlayer(loc.name.c_str()));
|
||||
if(!srp)
|
||||
return;
|
||||
srp->m_inventory_not_sent = true;
|
||||
}
|
||||
break;
|
||||
case InventoryLocation::NODEMETA:
|
||||
{
|
||||
v3s16 blockpos = getNodeBlockPos(loc.p);
|
||||
|
||||
NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
|
||||
if(meta)
|
||||
meta->inventoryModified();
|
||||
|
||||
MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
|
||||
if(block)
|
||||
block->raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
|
||||
setBlockNotSent(blockpos);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
Inventory* Server::getInventory(InventoryContext *c, std::string id)
|
||||
{
|
||||
if(id == "current_player")
|
||||
@@ -3533,12 +3622,10 @@ Inventory* Server::getInventory(InventoryContext *c, std::string id)
|
||||
p.X = stoi(fn.next(","));
|
||||
p.Y = stoi(fn.next(","));
|
||||
p.Z = stoi(fn.next(","));
|
||||
NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
|
||||
if(meta)
|
||||
return meta->getInventory();
|
||||
infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
|
||||
<<"no metadata found"<<std::endl;
|
||||
return NULL;
|
||||
|
||||
InventoryLocation loc;
|
||||
loc.setNodeMeta(p);
|
||||
return getInventory(loc);
|
||||
}
|
||||
|
||||
infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
|
||||
@@ -3566,21 +3653,15 @@ void Server::inventoryModified(InventoryContext *c, std::string id)
|
||||
p.Z = stoi(fn.next(","));
|
||||
v3s16 blockpos = getNodeBlockPos(p);
|
||||
|
||||
NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
|
||||
if(meta)
|
||||
meta->inventoryModified();
|
||||
|
||||
MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
|
||||
if(block)
|
||||
block->raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
|
||||
setBlockNotSent(blockpos);
|
||||
|
||||
InventoryLocation loc;
|
||||
loc.setNodeMeta(p);
|
||||
setInventoryModified(loc);
|
||||
return;
|
||||
}
|
||||
|
||||
infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
core::list<PlayerInfo> Server::getPlayerInfo()
|
||||
{
|
||||
@@ -4178,6 +4259,135 @@ void Server::SendBlocks(float dtime)
|
||||
}
|
||||
}
|
||||
|
||||
void Server::PrepareTextures() {
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
infostream<<"Server::PrepareTextures(): Calculate sha1 sums of textures"<<std::endl;
|
||||
|
||||
for(core::list<ModSpec>::Iterator i = m_mods.begin();
|
||||
i != m_mods.end(); i++){
|
||||
const ModSpec &mod = *i;
|
||||
std::string texturepath = mod.path + DIR_DELIM + "textures";
|
||||
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
|
||||
for(u32 j=0; j<dirlist.size(); j++){
|
||||
if(dirlist[j].dir) // Ignode dirs
|
||||
continue;
|
||||
std::string tname = dirlist[j].name;
|
||||
// if name contains illegal characters, ignore the texture
|
||||
if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
|
||||
errorstream<<"Server: ignoring illegal texture name: \""
|
||||
<<tname<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
std::string tpath = texturepath + DIR_DELIM + tname;
|
||||
// Read data
|
||||
std::ifstream fis(tpath.c_str(), std::ios_base::binary);
|
||||
if(fis.good() == false){
|
||||
errorstream<<"Server::PrepareTextures(): Could not open \""
|
||||
<<tname<<"\" for reading"<<std::endl;
|
||||
continue;
|
||||
}
|
||||
std::ostringstream tmp_os(std::ios_base::binary);
|
||||
bool bad = false;
|
||||
for(;;){
|
||||
char buf[1024];
|
||||
fis.read(buf, 1024);
|
||||
std::streamsize len = fis.gcount();
|
||||
tmp_os.write(buf, len);
|
||||
if(fis.eof())
|
||||
break;
|
||||
if(!fis.good()){
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(bad){
|
||||
errorstream<<"Server::PrepareTextures(): Failed to read \""
|
||||
<<tname<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
if(tmp_os.str().length() == 0){
|
||||
errorstream<<"Server::PrepareTextures(): Empty file \""
|
||||
<<tpath<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
SHA1 sha1;
|
||||
sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
|
||||
|
||||
unsigned char *digest = sha1.getDigest();
|
||||
std::string digest_string = base64_encode(digest, 20);
|
||||
|
||||
free(digest);
|
||||
|
||||
// Put in list
|
||||
this->m_Textures[tname] = TextureInformation(tpath,digest_string);
|
||||
infostream<<"Server::PrepareTextures(): added sha1 for "<< tname <<std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SendableTextureAnnouncement
|
||||
{
|
||||
std::string name;
|
||||
std::string sha1_digest;
|
||||
|
||||
SendableTextureAnnouncement(const std::string name_="",
|
||||
const std::string sha1_digest_=""):
|
||||
name(name_),
|
||||
sha1_digest(sha1_digest_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void Server::SendTextureAnnouncement(u16 peer_id){
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
infostream<<"Server::SendTextureAnnouncement()"<<std::endl;
|
||||
|
||||
core::list<SendableTextureAnnouncement> texture_announcements;
|
||||
|
||||
for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
|
||||
|
||||
// Put in list
|
||||
texture_announcements.push_back(
|
||||
SendableTextureAnnouncement(i->first, i->second.sha1_digest));
|
||||
}
|
||||
|
||||
//send announcements
|
||||
|
||||
/*
|
||||
u16 command
|
||||
u32 number of textures
|
||||
for each texture {
|
||||
u16 length of name
|
||||
string name
|
||||
u16 length of digest string
|
||||
string sha1_digest
|
||||
}
|
||||
*/
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
|
||||
writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
|
||||
writeU16(os, texture_announcements.size());
|
||||
|
||||
for(core::list<SendableTextureAnnouncement>::Iterator
|
||||
j = texture_announcements.begin();
|
||||
j != texture_announcements.end(); j++){
|
||||
os<<serializeString(j->name);
|
||||
os<<serializeString(j->sha1_digest);
|
||||
}
|
||||
|
||||
// Make data buffer
|
||||
std::string s = os.str();
|
||||
infostream<<"Server::SendTextureAnnouncement(): Send to client"<<std::endl;
|
||||
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
|
||||
|
||||
// Send as reliable
|
||||
m_con.Send(peer_id, 0, data, true);
|
||||
|
||||
}
|
||||
|
||||
struct SendableTexture
|
||||
{
|
||||
std::string name;
|
||||
@@ -4192,113 +4402,114 @@ struct SendableTexture
|
||||
{}
|
||||
};
|
||||
|
||||
void Server::SendTextures(u16 peer_id)
|
||||
{
|
||||
void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
infostream<<"Server::SendTextures(): Sending textures to client"<<std::endl;
|
||||
|
||||
infostream<<"Server::SendTexturesRequested(): Sending textures to client"<<std::endl;
|
||||
|
||||
/* Read textures */
|
||||
|
||||
|
||||
// Put 5kB in one bunch (this is not accurate)
|
||||
u32 bytes_per_bunch = 5000;
|
||||
|
||||
|
||||
core::array< core::list<SendableTexture> > texture_bunches;
|
||||
texture_bunches.push_back(core::list<SendableTexture>());
|
||||
|
||||
|
||||
u32 texture_size_bunch_total = 0;
|
||||
core::list<ModSpec> mods = getMods(m_modspaths);
|
||||
for(core::list<ModSpec>::Iterator i = mods.begin();
|
||||
i != mods.end(); i++){
|
||||
ModSpec mod = *i;
|
||||
std::string texturepath = mod.path + DIR_DELIM + "textures";
|
||||
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
|
||||
for(u32 j=0; j<dirlist.size(); j++){
|
||||
if(dirlist[j].dir) // Ignode dirs
|
||||
continue;
|
||||
std::string tname = dirlist[j].name;
|
||||
std::string tpath = texturepath + DIR_DELIM + tname;
|
||||
// Read data
|
||||
std::ifstream fis(tpath.c_str(), std::ios_base::binary);
|
||||
if(fis.good() == false){
|
||||
errorstream<<"Server::SendTextures(): Could not open \""
|
||||
<<tname<<"\" for reading"<<std::endl;
|
||||
continue;
|
||||
}
|
||||
std::ostringstream tmp_os(std::ios_base::binary);
|
||||
bool bad = false;
|
||||
for(;;){
|
||||
char buf[1024];
|
||||
fis.read(buf, 1024);
|
||||
std::streamsize len = fis.gcount();
|
||||
tmp_os.write(buf, len);
|
||||
texture_size_bunch_total += len;
|
||||
if(fis.eof())
|
||||
break;
|
||||
if(!fis.good()){
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(bad){
|
||||
errorstream<<"Server::SendTextures(): Failed to read \""
|
||||
<<tname<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
/*infostream<<"Server::SendTextures(): Loaded \""
|
||||
<<tname<<"\""<<std::endl;*/
|
||||
// Put in list
|
||||
texture_bunches[texture_bunches.size()-1].push_back(
|
||||
SendableTexture(tname, tpath, tmp_os.str()));
|
||||
|
||||
// Start next bunch if got enough data
|
||||
if(texture_size_bunch_total >= bytes_per_bunch){
|
||||
texture_bunches.push_back(core::list<SendableTexture>());
|
||||
texture_size_bunch_total = 0;
|
||||
|
||||
for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
|
||||
if(m_Textures.find(i->name) == m_Textures.end()){
|
||||
errorstream<<"Server::SendTexturesRequested(): Client asked for "
|
||||
<<"unknown texture \""<<(i->name)<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
//TODO get path + name
|
||||
std::string tpath = m_Textures[(*i).name].path;
|
||||
|
||||
// Read data
|
||||
std::ifstream fis(tpath.c_str(), std::ios_base::binary);
|
||||
if(fis.good() == false){
|
||||
errorstream<<"Server::SendTexturesRequested(): Could not open \""
|
||||
<<tpath<<"\" for reading"<<std::endl;
|
||||
continue;
|
||||
}
|
||||
std::ostringstream tmp_os(std::ios_base::binary);
|
||||
bool bad = false;
|
||||
for(;;){
|
||||
char buf[1024];
|
||||
fis.read(buf, 1024);
|
||||
std::streamsize len = fis.gcount();
|
||||
tmp_os.write(buf, len);
|
||||
texture_size_bunch_total += len;
|
||||
if(fis.eof())
|
||||
break;
|
||||
if(!fis.good()){
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(bad){
|
||||
errorstream<<"Server::SendTexturesRequested(): Failed to read \""
|
||||
<<(*i).name<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
/*infostream<<"Server::SendTexturesRequested(): Loaded \""
|
||||
<<tname<<"\""<<std::endl;*/
|
||||
// Put in list
|
||||
texture_bunches[texture_bunches.size()-1].push_back(
|
||||
SendableTexture((*i).name, tpath, tmp_os.str()));
|
||||
|
||||
// Start next bunch if got enough data
|
||||
if(texture_size_bunch_total >= bytes_per_bunch){
|
||||
texture_bunches.push_back(core::list<SendableTexture>());
|
||||
texture_size_bunch_total = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Create and send packets */
|
||||
|
||||
u32 num_bunches = texture_bunches.size();
|
||||
for(u32 i=0; i<num_bunches; i++)
|
||||
{
|
||||
/*
|
||||
u16 command
|
||||
u16 total number of texture bunches
|
||||
u16 index of this bunch
|
||||
u32 number of textures in this bunch
|
||||
for each texture {
|
||||
u16 length of name
|
||||
string name
|
||||
u32 length of data
|
||||
data
|
||||
}
|
||||
*/
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
|
||||
writeU16(os, TOCLIENT_TEXTURES);
|
||||
writeU16(os, num_bunches);
|
||||
writeU16(os, i);
|
||||
writeU32(os, texture_bunches[i].size());
|
||||
|
||||
for(core::list<SendableTexture>::Iterator
|
||||
j = texture_bunches[i].begin();
|
||||
j != texture_bunches[i].end(); j++){
|
||||
os<<serializeString(j->name);
|
||||
os<<serializeLongString(j->data);
|
||||
u32 num_bunches = texture_bunches.size();
|
||||
for(u32 i=0; i<num_bunches; i++)
|
||||
{
|
||||
/*
|
||||
u16 command
|
||||
u16 total number of texture bunches
|
||||
u16 index of this bunch
|
||||
u32 number of textures in this bunch
|
||||
for each texture {
|
||||
u16 length of name
|
||||
string name
|
||||
u32 length of data
|
||||
data
|
||||
}
|
||||
*/
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
|
||||
writeU16(os, TOCLIENT_TEXTURES);
|
||||
writeU16(os, num_bunches);
|
||||
writeU16(os, i);
|
||||
writeU32(os, texture_bunches[i].size());
|
||||
|
||||
for(core::list<SendableTexture>::Iterator
|
||||
j = texture_bunches[i].begin();
|
||||
j != texture_bunches[i].end(); j++){
|
||||
os<<serializeString(j->name);
|
||||
os<<serializeLongString(j->data);
|
||||
}
|
||||
|
||||
// Make data buffer
|
||||
std::string s = os.str();
|
||||
infostream<<"Server::SendTexturesRequested(): bunch "<<i<<"/"<<num_bunches
|
||||
<<" textures="<<texture_bunches[i].size()
|
||||
<<" size=" <<s.size()<<std::endl;
|
||||
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
|
||||
// Send as reliable
|
||||
m_con.Send(peer_id, 0, data, true);
|
||||
}
|
||||
|
||||
// Make data buffer
|
||||
std::string s = os.str();
|
||||
infostream<<"Server::SendTextures(): bunch "<<i<<"/"<<num_bunches
|
||||
<<" textures="<<texture_bunches[i].size()
|
||||
<<" size=" <<s.size()<<std::endl;
|
||||
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
|
||||
// Send as reliable
|
||||
m_con.Send(peer_id, 0, data, true);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4312,13 +4523,12 @@ void Server::HandlePlayerHP(Player *player, s16 damage)
|
||||
if(srp->m_respawn_active)
|
||||
return;
|
||||
|
||||
if(damage == 0)
|
||||
return;
|
||||
|
||||
if(player->hp > damage)
|
||||
{
|
||||
player->hp -= damage;
|
||||
SendPlayerHP(player);
|
||||
if(damage != 0){
|
||||
player->hp -= damage;
|
||||
SendPlayerHP(player);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4327,7 +4537,8 @@ void Server::HandlePlayerHP(Player *player, s16 damage)
|
||||
|
||||
player->hp = 0;
|
||||
|
||||
//TODO: Throw items around
|
||||
// Trigger scripted stuff
|
||||
scriptapi_on_dieplayer(m_lua, srp);
|
||||
|
||||
// Handle players that are not connected
|
||||
if(player->peer_id == PEER_ID_INEXISTENT){
|
||||
@@ -4565,6 +4776,17 @@ IWritableCraftItemDefManager* Server::getWritableCraftItemDefManager()
|
||||
return m_craftitemdef;
|
||||
}
|
||||
|
||||
const ModSpec* Server::getModSpec(const std::string &modname)
|
||||
{
|
||||
for(core::list<ModSpec>::Iterator i = m_mods.begin();
|
||||
i != m_mods.end(); i++){
|
||||
const ModSpec &mod = *i;
|
||||
if(mod.name == modname)
|
||||
return &mod;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
v3f findSpawnPos(ServerMap &map)
|
||||
{
|
||||
//return v3f(50,50,50)*BS;
|
||||
|
||||
41
src/server.h
41
src/server.h
@@ -32,6 +32,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "gamedef.h"
|
||||
#include "serialization.h" // For SER_FMT_VER_INVALID
|
||||
#include "serverremoteplayer.h"
|
||||
#include "mods.h"
|
||||
#include "inventorymanager.h"
|
||||
struct LuaState;
|
||||
typedef struct lua_State lua_State;
|
||||
class IWritableToolDefManager;
|
||||
@@ -234,6 +236,28 @@ struct PrioritySortedBlockTransfer
|
||||
u16 peer_id;
|
||||
};
|
||||
|
||||
struct TextureRequest
|
||||
{
|
||||
std::string name;
|
||||
|
||||
TextureRequest(const std::string &name_=""):
|
||||
name(name_)
|
||||
{}
|
||||
};
|
||||
|
||||
struct TextureInformation
|
||||
{
|
||||
std::string path;
|
||||
std::string sha1_digest;
|
||||
|
||||
TextureInformation(const std::string path_="",
|
||||
const std::string sha1_digest_=""):
|
||||
path(path_),
|
||||
sha1_digest(sha1_digest_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class RemoteClient
|
||||
{
|
||||
public:
|
||||
@@ -412,8 +436,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
|
||||
/*
|
||||
Shall be called with the environment and the connection locked.
|
||||
*/
|
||||
Inventory* getInventory(InventoryContext *c, std::string id);
|
||||
void inventoryModified(InventoryContext *c, std::string id);
|
||||
Inventory* getInventory(const InventoryLocation &loc);
|
||||
void setInventoryModified(const InventoryLocation &loc);
|
||||
|
||||
// Connection must be locked when called
|
||||
std::wstring getStatusString();
|
||||
@@ -502,6 +526,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
|
||||
IWritableCraftDefManager* getWritableCraftDefManager();
|
||||
IWritableCraftItemDefManager* getWritableCraftItemDefManager();
|
||||
|
||||
const ModSpec* getModSpec(const std::string &modname);
|
||||
|
||||
private:
|
||||
|
||||
// con::PeerHandler implementation.
|
||||
@@ -560,7 +586,11 @@ class Server : public con::PeerHandler, public MapEventReceiver,
|
||||
// Sends blocks to clients (locks env and con on its own)
|
||||
void SendBlocks(float dtime);
|
||||
|
||||
void SendTextures(u16 peer_id);
|
||||
void PrepareTextures();
|
||||
|
||||
void SendTextureAnnouncement(u16 peer_id);
|
||||
|
||||
void SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend);
|
||||
|
||||
/*
|
||||
Something random
|
||||
@@ -646,6 +676,9 @@ class Server : public con::PeerHandler, public MapEventReceiver,
|
||||
// CraftItem definition manager
|
||||
IWritableCraftItemDefManager *m_craftitemdef;
|
||||
|
||||
// Mods
|
||||
core::list<ModSpec> m_mods;
|
||||
|
||||
/*
|
||||
Threads
|
||||
*/
|
||||
@@ -737,6 +770,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
|
||||
|
||||
friend class EmergeThread;
|
||||
friend class RemoteClient;
|
||||
|
||||
std::map<std::string,TextureInformation> m_Textures;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -31,11 +31,11 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env):
|
||||
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_time_from_last_punch(0),
|
||||
m_position_not_sent(false)
|
||||
{
|
||||
}
|
||||
@@ -43,9 +43,12 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 pee
|
||||
const char *name_):
|
||||
Player(env->getGameDef()),
|
||||
ServerActiveObject(env, pos_),
|
||||
m_last_good_position(0,0,0),
|
||||
m_last_good_position_age(0),
|
||||
m_inventory_not_sent(false),
|
||||
m_hp_not_sent(false),
|
||||
m_is_in_environment(false),
|
||||
m_time_from_last_punch(0),
|
||||
m_position_not_sent(false)
|
||||
{
|
||||
setPosition(pos_);
|
||||
@@ -93,6 +96,8 @@ bool ServerRemotePlayer::unlimitedTransferDistance() const
|
||||
|
||||
void ServerRemotePlayer::step(float dtime, bool send_recommended)
|
||||
{
|
||||
m_time_from_last_punch += dtime;
|
||||
|
||||
if(send_recommended == false)
|
||||
return;
|
||||
|
||||
@@ -157,9 +162,14 @@ void ServerRemotePlayer::punch(ServerActiveObject *puncher,
|
||||
HittingProperties hitprop = getHittingProperties(&mp, &tp,
|
||||
time_from_last_punch);
|
||||
|
||||
actionstream<<"Player "<<getName()<<" punched by "
|
||||
<<puncher->getDescription()<<", damage "<<hitprop.hp
|
||||
<<" HP"<<std::endl;
|
||||
|
||||
setHP(getHP() - hitprop.hp);
|
||||
puncher->damageWieldedItem(hitprop.wear);
|
||||
|
||||
|
||||
if(hitprop.hp != 0)
|
||||
{
|
||||
std::ostringstream os(std::ios::binary);
|
||||
// command (1 = punched)
|
||||
|
||||
@@ -74,7 +74,8 @@ class ServerRemotePlayer : public Player, public ServerActiveObject
|
||||
void rightClick(ServerActiveObject *clicker);
|
||||
void setPos(v3f pos);
|
||||
void moveTo(v3f pos, bool continuous);
|
||||
virtual std::string getDescription(){return getName();}
|
||||
virtual std::string getDescription()
|
||||
{return std::string("player ")+getName();}
|
||||
|
||||
virtual void getWieldDiggingProperties(ToolDiggingProperties *dst);
|
||||
virtual void damageWieldedItem(u16 amount);
|
||||
@@ -93,6 +94,8 @@ class ServerRemotePlayer : public Player, public ServerActiveObject
|
||||
bool m_hp_not_sent;
|
||||
bool m_respawn_active;
|
||||
bool m_is_in_environment;
|
||||
// Incremented by step(), read and reset by Server
|
||||
float m_time_from_last_punch;
|
||||
|
||||
private:
|
||||
bool m_position_not_sent;
|
||||
|
||||
@@ -96,12 +96,7 @@ class CToolDefManager: public IWritableToolDefManager
|
||||
virtual const ToolDefinition* getToolDefinition(const std::string &toolname_) const
|
||||
{
|
||||
// Convert name according to possible alias
|
||||
std::string toolname = toolname_;
|
||||
std::map<std::string, std::string>::const_iterator i;
|
||||
i = m_aliases.find(toolname);
|
||||
if(i != m_aliases.end()){
|
||||
toolname = i->second;
|
||||
}
|
||||
std::string toolname = getAlias(toolname_);
|
||||
// Get the definition
|
||||
core::map<std::string, ToolDefinition*>::Node *n;
|
||||
n = m_tool_definitions.find(toolname);
|
||||
@@ -130,6 +125,15 @@ class CToolDefManager: public IWritableToolDefManager
|
||||
}
|
||||
return def->properties;
|
||||
}
|
||||
virtual std::string getAlias(const std::string &name) const
|
||||
{
|
||||
std::map<std::string, std::string>::const_iterator i;
|
||||
i = m_aliases.find(name);
|
||||
if(i != m_aliases.end())
|
||||
return i->second;
|
||||
return name;
|
||||
}
|
||||
// IWritableToolDefManager
|
||||
virtual bool registerTool(std::string toolname, const ToolDefinition &def)
|
||||
{
|
||||
infostream<<"registerTool: registering tool \""<<toolname<<"\""<<std::endl;
|
||||
|
||||
@@ -38,7 +38,7 @@ struct ToolDiggingProperties
|
||||
float dd_crumbliness;
|
||||
float dd_cuttability;
|
||||
|
||||
ToolDiggingProperties(float full_punch_interval_=1.0,
|
||||
ToolDiggingProperties(float full_punch_interval_=2.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);
|
||||
};
|
||||
@@ -69,6 +69,7 @@ class IToolDefManager
|
||||
virtual std::string getImagename(const std::string &toolname) const =0;
|
||||
virtual ToolDiggingProperties getDiggingProperties(
|
||||
const std::string &toolname) const =0;
|
||||
virtual std::string getAlias(const std::string &name) const =0;
|
||||
|
||||
virtual void serialize(std::ostream &os)=0;
|
||||
};
|
||||
@@ -82,6 +83,7 @@ class IWritableToolDefManager : public IToolDefManager
|
||||
virtual std::string getImagename(const std::string &toolname) const =0;
|
||||
virtual ToolDiggingProperties getDiggingProperties(
|
||||
const std::string &toolname) const =0;
|
||||
virtual std::string getAlias(const std::string &name) const =0;
|
||||
|
||||
virtual bool registerTool(std::string toolname, const ToolDefinition &def)=0;
|
||||
virtual void clear()=0;
|
||||
|
||||
Reference in New Issue
Block a user