Compare commits

...

70 Commits

Author SHA1 Message Date
sapier
c17133d80a added player link support 2012-01-15 22:41:10 +01:00
sapier
14a64000ea add support for entity linking 2012-01-15 22:22:07 +01:00
sapier
e3122ae727 fix object message type sent 2012-01-15 21:44:51 +01:00
sapier
65ac1d46b3 split content_sao.cpp and content_sao.h to multiple files 2012-01-15 21:35:25 +01:00
sapier
dd73852ce4 split content_cao.cpp file into multiple separate files 2012-01-15 20:55:30 +01:00
sapier
3454e67793 added new entity style irregular_cube 2012-01-15 20:30:26 +01:00
sapier
0c78767754 fixed invalid comment for plant mesh declaration 2012-01-15 20:28:39 +01:00
sapier
f0679969b2 added plantlike luaentity 2012-01-15 20:22:41 +01:00
sapier
285f5a0259 added lua command get_nodes_inside_radius 2012-01-15 20:09:55 +01:00
sapier
71186974fa fixed missing removal in static fix 2012-01-15 20:06:56 +01:00
sapier
525bc8855f added derived object to add linkable object support 2012-01-15 19:55:58 +01:00
sapier
de166e75a1 sao prototype global variables no longer depend on link order to be correctly added to factory 2012-01-15 19:43:31 +01:00
Perttu Ahola
569156b013 Call this 0.4.dev-20120106-1 2012-01-06 20:41:52 +02:00
Perttu Ahola
6d4bc012f0 Fix key change menu a bit 2012-01-06 19:50:40 +02:00
Perttu Ahola
2f5c28aaf1 ObjectRef:setpos() to move player properly (a bit shortcuttish implementation) 2012-01-06 19:17:44 +02:00
Perttu Ahola
4f2c1e36a1 Implement minetest.register_on_dieplayer() 2012-01-06 00:12:33 +02:00
Perttu Ahola
bc743ca7ce Add missing checks to texture caching 2012-01-04 00:37:46 +02:00
Perttu Ahola
f9d7e399b2 Limit range of ABM timer initial value randomization 2012-01-03 13:49:47 +02:00
Perttu Ahola
3e6f824e6c Use free rather than delete for malloc'd memory 2012-01-02 21:42:33 +02:00
Perttu Ahola
6286c555d4 Initialize ABM timer to random value to spread processing 2012-01-02 21:06:38 +02:00
Perttu Ahola
4630281318 Fix ABM trigger chance being often way too high 2012-01-02 20:26:33 +02:00
Perttu Ahola
cd0019acd2 Fix server sending stuff before textures have been sent 2012-01-02 17:44:00 +02:00
Perttu Ahola
e82a76e438 Mark ObjectRef::get_entity_name() deprecated 2012-01-02 17:33:03 +02:00
Perttu Ahola
ab57fbe4ca Add name field to registered entities 2012-01-02 16:26:40 +02:00
Perttu Ahola
56f55ab1af Add ObjectRef:getvelocity(), ObjectRef:setyaw() and ObjectRef:getyaw() 2012-01-02 16:19:52 +02:00
Perttu Ahola
2445cbbbdc Add ObjectRef:get_luaentity() 2012-01-02 16:08:59 +02:00
Perttu Ahola
48131bf988 Call this 0.4.dev-20120102-1 2012-01-02 13:51:43 +02:00
Perttu Ahola
2b9596fe9b Make text area in message dialog a bit larger 2012-01-02 13:34:24 +02:00
Perttu Ahola
0e1f448b61 Texture cache on client (mostly made by sapier) (breaks network compatibility) 2012-01-02 13:31:50 +02:00
Perttu Ahola
ff82b95800 ObjectRef:get_entity_name() and fixing of comments in default/init.lua 2012-01-02 13:12:56 +02:00
Perttu Ahola
49b7055cb3 Make add_entity return a reference to added entity (or nil) 2012-01-02 12:48:25 +02:00
Perttu Ahola
cb88f7b6d4 Clean up InvRef documentation in default/init.lua a bit 2012-01-02 03:18:23 +02:00
Perttu Ahola
9425fb8192 Improve mini Lua reference 2012-01-02 02:59:14 +02:00
Perttu Ahola
e48ccd7943 Add ObjectRef:get_inventory() and add stuff to documentation comments 2012-01-02 02:59:14 +02:00
Perttu Ahola
6be5441176 Working implementation of experimental:luafurnace 2012-01-02 02:59:14 +02:00
Perttu Ahola
d5ba7ebaf0 Random fixes to InvRef related stuff and a broken luafurnace 2012-01-02 02:59:14 +02:00
Perttu Ahola
270a482740 Add InvRef:get_list() and InvRef:set_list() and fix some things (untested) 2012-01-02 02:59:14 +02:00
Perttu Ahola
e0b4890794 Add minetest.get_inventory(location), untested 2012-01-02 02:57:14 +02:00
Perttu Ahola
247e8b6e5d A small robustness addition to ItemStack 2012-01-02 01:49:38 +02:00
Perttu Ahola
b760e2ba23 Rename InvStack to ItemStack 2012-01-02 01:49:38 +02:00
Perttu Ahola
103173fc9b Add InvRef and InvStack (currently untested and unusable) 2012-01-02 01:49:38 +02:00
Perttu Ahola
70ed371d0c Add default: to everything in default/init.lua (...hopefully doesn't break anything) 2012-01-01 21:31:47 +02:00
Perttu Ahola
81d3485109 Fix segfault when generating stuff on world boundaries 2012-01-01 21:01:55 +02:00
Perttu Ahola
7b7b68cdab Correctly pop stuff from the Lua stack in script_load() 2011-12-31 14:41:57 +02:00
Giuseppe Bilotta
135a65e200 Add virtual destructors to abstract classes
IRespawnInitiator and InventoryActions are abstract classes, but they
were missing a virtual destructor. Define it, even if it does nothing
and its absence most likely makes no difference other tha causing
warnings during compile.
2011-12-28 20:50:21 +02:00
Perttu Ahola
123529e5eb Fix mirrored sign texture 2011-12-28 18:29:33 +02:00
Perttu Ahola
e81989a0d8 Add wooden planks to creative inventory 2011-12-28 18:24:09 +02:00
Perttu Ahola
1c15f53318 Add EnvRef:get_objects_inside_radius(pos, radius) 2011-12-28 18:18:08 +02:00
Perttu Ahola
7937813c98 Add get_look_dir(), get_look_pitch() and get_look_yaw() for players 2011-12-28 17:34:07 +02:00
Perttu Ahola
ad4040d982 Fix minetest.env:get_player_by_name(nil) causing segfault and similar things 2011-12-28 16:25:29 +02:00
Perttu Ahola
69579306dd Extend load screen maximum time 2011-12-11 16:52:19 +02:00
Perttu Ahola
bd21f00f0a Add minetest.get_modpath(modname) 2011-12-11 16:49:40 +02:00
Perttu Ahola
012bcbcb48 add_luaentity->add_entity in mods/experimental 2011-12-11 01:52:37 +02:00
Perttu Ahola
e06d4555bf Call this 0.4.dev-20111209-1 2011-12-09 11:36:47 +02:00
Perttu Ahola
abd106bacb Enforce modname naming convention 2011-12-04 18:26:05 +02:00
Perttu Ahola
008de2fb8f Delete unknown LuaEntities when punched 2011-12-04 16:25:27 +02:00
Perttu Ahola
2e67fa3e48 Improve /spawnentity a bit 2011-12-04 16:20:54 +02:00
Perttu Ahola
ea36951bc4 Rename EnvRef:add_luaentity to EnvRef:add_entity 2011-12-04 16:08:37 +02:00
Perttu Ahola
09c48b60bd Add EnvRef:get_node_light(pos, timeofday) 2011-12-04 15:55:37 +02:00
Perttu Ahola
4cc117ddf6 Properly use time_from_last_punch for limiting PvP punch damage 2011-12-04 14:43:01 +02:00
Kahrl
ceaf8edade Use plain IBillboardSceneNode instead of MyBillboardSceneNode (improves
Irrlicht 1.8 compat); also find dungeon master's fireball texture
again; add /spawnentity command
2011-12-04 13:27:30 +02:00
Perttu Ahola
520200d597 Check symlinks with stat() to know if they are directories or not 2011-12-04 13:02:00 +02:00
Perttu Ahola
ab67985d21 Add support for unix filesystems which yield DT_UNKNOWN in dirent->d_type, falling back on stat(). 2011-12-04 12:49:58 +02:00
Perttu Ahola
bc5cc638fc Fix player not dying when beated to death by other player 2011-12-04 03:56:22 +02:00
Perttu Ahola
bff8be8b76 Fix getting two old-style minerals per digged node 2011-12-04 03:47:55 +02:00
Perttu Ahola
3e95b8a158 Determine light_propagates from paramtype 2011-12-04 03:45:02 +02:00
Perttu Ahola
e8539d4dae Add experimental TNT's old name as an alias 2011-12-04 02:16:23 +02:00
Perttu Ahola
1907b31da7 Add furnace to legacy aliases 2011-12-04 02:15:05 +02:00
Perttu Ahola
6145a135bd Make ToolItem and MaterialItem to convert names by aliases at creation time too (necessary for eg. crafting) 2011-12-04 02:12:45 +02:00
Perttu Ahola
97c3bc408b Fix fence name 2011-12-04 02:12:43 +02:00
81 changed files with 9306 additions and 6836 deletions

View File

@@ -10,7 +10,7 @@ project(minetest)
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
set(VERSION_MAJOR 0)
set(VERSION_MINOR 4)
set(VERSION_PATCH dev-20111204-1)
set(VERSION_PATCH dev-20120106-1)
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
MESSAGE(STATUS "*** Will build version ${VERSION_STRING} ***")

View File

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

View File

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

View File

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

View File

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

View File

Before

Width:  |  Height:  |  Size: 603 B

After

Width:  |  Height:  |  Size: 603 B

View File

@@ -94,6 +94,7 @@ configure_file(
)
set(common_SRCS
inventorymanager.cpp
mods.cpp
serverremoteplayer.cpp
content_abm.cpp
@@ -106,6 +107,13 @@ set(common_SRCS
scriptapi.cpp
script.cpp
log.cpp
content_sao_firefly.cpp
content_sao_item.cpp
content_sao_lua.cpp
content_sao_mobv2.cpp
content_sao_oerkki1.cpp
content_sao_rat.cpp
content_sao_test.cpp
content_sao.cpp
mapgen.cpp
content_nodemeta.cpp
@@ -114,6 +122,7 @@ set(common_SRCS
collision.cpp
nodemetadata.cpp
serverobject.cpp
serverlinkableobject.cpp
noise.cpp
mineral.cpp
porting.cpp
@@ -158,9 +167,16 @@ endif()
# Client sources
set(minetest_SRCS
${common_SRCS}
MyBillboardSceneNode.cpp
content_mapblock.cpp
content_cao.cpp
content_cao_player.cpp
content_cao_item.cpp
content_cao_lua.cpp
content_cao_rat.cpp
content_cao_oerkki1.cpp
content_cao_firefly.cpp
content_cao_mobv2.cpp
content_cao_test.cpp
mesh.cpp
mapblock_mesh.cpp
farmesh.cpp
@@ -168,6 +184,7 @@ set(minetest_SRCS
camera.cpp
clouds.cpp
clientobject.cpp
clientlinkableobject.cpp
guiMainMenu.cpp
guiKeyChangeMenu.cpp
guiMessageMenu.cpp

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,123 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2012 sapier sapier at gmx dot net
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 "clientlinkableobject.h"
ClientLinkableObject::ClientLinkableObject() {
this->m_Parent = NULL;
}
ClientLinkableObject::~ClientLinkableObject() {
if (this->isLinked())
this->unlink(this);
}
void ClientLinkableObject::link(ClientLinkableObject* entity) {
//TODO check if entity is already linkt (shouldn't be the case but just to be sure)
this->m_LinkedObjects.push_back(entity);
}
void ClientLinkableObject::unlink(ClientLinkableObject* entity) {
this->m_LinkedObjects.remove(entity);
}
void ClientLinkableObject::stepLinkedObjects(v3f pos,float dtime) {
for(std::list<ClientLinkableObject*>::iterator i = this->m_LinkedObjects.begin();
i != this->m_LinkedObjects.end(); i++) {
(*i)->setPosition(pos,dtime);
}
}
bool ClientLinkableObject::handleLinkUnlinkMessages(u8 cmd,std::istringstream* is,ClientEnvironment *m_env) {
if(cmd == AO_Message_type::Link) // Link entity
{
//Object to link entity to
u16 object_id = readU16(*is);
//offset against linked object
v3f offset = readV3F1000(*is);
ClientActiveObject* parent_cao = m_env->getActiveObject(object_id);
ClientLinkableObject* parent = dynamic_cast<ClientLinkableObject*>(parent_cao);
if (parent != NULL) {
this->linkEntity(offset,parent);
}
else {
errorstream << "Invalid object to link to!" << std::endl;
}
return true;
}
else if(cmd == AO_Message_type::UnLink) // UnLink entity
{
if (this->m_Parent == NULL) {
errorstream << "Unlinking object not linked!" << std::endl;
}
this->unlinkEntity();
return true;
}
return false;
}
bool ClientLinkableObject::linkEntity(v3f offset, ClientLinkableObject* parent) {
//already linked unlink first
if (this->m_Parent != NULL) {
return false;
}
//TODO add linkchain support
if (this->m_LinkedObjects.size() > 0) {
return false;
}
parent->link(this);
updateLinkState(true);
this->m_linkOffset = offset;
this->m_Parent = parent;
return true;
}
bool ClientLinkableObject::unlinkEntity() {
if (this->m_Parent != NULL) {
updateLinkState(false);
this->m_Parent->unlink(this);
this->m_Parent = NULL;
return true;
}
return false;
}
bool ClientLinkableObject::isLinked() {
if (this->m_Parent != NULL)
return true;
else
return false;
}

View File

@@ -0,0 +1,65 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2012 sapier sapier at gmx dot net
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 CLIENTLINKABLEOBJECT_H_
#define CLIENTLINKABLEOBJECT_H_
#include <list>
#include <sstream>
#include <irrlichttypes.h>
#include "clientobject.h"
#include "environment.h"
#include "content_object.h"
#include "utility.h"
#include "log.h"
class ClientLinkableObject {
public:
ClientLinkableObject();
~ClientLinkableObject();
//internal communication between entitys NOT to be used by user
void link(ClientLinkableObject* entity);
void unlink(ClientLinkableObject* entity);
virtual void setPosition(v3f toset, float dtime) = 0;
virtual void updateLinkState(bool value) = 0;
protected:
void stepLinkedObjects(v3f pos,float dtime);
bool handleLinkUnlinkMessages(u8 cmd,std::istringstream* is,ClientEnvironment *m_env);
//user driven functions (exported by lua)
bool linkEntity(v3f offset, ClientLinkableObject* parent);
bool unlinkEntity();
bool isLinked();
v3f m_linkOffset;
private:
ClientLinkableObject* m_Parent;
std::list<ClientLinkableObject*> m_LinkedObjects;
};
#endif /* CLIENTLINKABLEOBJECT_H_ */

View File

@@ -43,8 +43,8 @@ ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef,
ClientEnvironment *env)
{
// Find factory function
core::map<u16, Factory>::Node *n;
n = m_types.find(type);
core::map<u8, Factory>::Node *n;
n = ClientActiveObject::getTypes().find(type);
if(n == NULL)
{
// If factory is not found, just return.
@@ -58,13 +58,13 @@ ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef,
return object;
}
void ClientActiveObject::registerType(u16 type, Factory f)
void ClientActiveObject::registerType(u8 type, Factory f)
{
core::map<u16, Factory>::Node *n;
n = m_types.find(type);
core::map<u8, Factory>::Node *n;
n = ClientActiveObject::getTypes().find(type);
if(n)
return;
m_types.insert(type, f);
ClientActiveObject::getTypes().insert(type, f);
}

View File

@@ -1,6 +1,6 @@
/*
Minetest-c55
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2010-2012 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
@@ -81,12 +81,16 @@ class ClientActiveObject : public ActiveObject
protected:
// Used for creating objects based on type
typedef ClientActiveObject* (*Factory)(IGameDef *gamedef, ClientEnvironment *env);
static void registerType(u16 type, Factory f);
static void registerType(u8 type, Factory f);
IGameDef *m_gamedef;
ClientEnvironment *m_env;
private:
// Used for creating objects based on type
static core::map<u16, Factory> m_types;
static core::map<u8, Factory>& getTypes()
{
static core::map<u8, Factory> types;
return types;
}
};
struct DistanceSortedActiveObject

View File

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

View File

@@ -23,6 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gamedef.h"
#include "nodedef.h"
#include "content_sao.h"
#include "content_sao_rat.h"
#include "content_sao_mobv2.h"
#include "content_sao_oerkki1.h"
#include "settings.h"
#include "mapblock.h" // For getNodeBlockPos
#include "mapgen.h" // For mapgen::make_tree

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
Minetest-c55
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2010-2012 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
@@ -20,5 +20,104 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef CONTENT_CAO_HEADER
#define CONTENT_CAO_HEADER
#include "tile.h"
#include "environment.h"
#include "settings.h"
#include <ICameraSceneNode.h>
#include <ITextSceneNode.h>
#include <IBillboardSceneNode.h>
#include "serialization.h" // For decompressZlib
#include "gamedef.h"
#include "clientobject.h"
#include "content_object.h"
#include "mesh.h"
#include "utility.h" // For IntervalLimiter
class Settings;
/*
SmoothTranslator
*/
struct SmoothTranslator
{
v3f vect_old;
v3f vect_show;
v3f vect_aim;
f32 anim_counter;
f32 anim_time;
f32 anim_time_counter;
bool aim_is_end;
SmoothTranslator():
vect_old(0,0,0),
vect_show(0,0,0),
vect_aim(0,0,0),
anim_counter(0),
anim_time(0),
anim_time_counter(0),
aim_is_end(true)
{}
void init(v3f vect)
{
vect_old = vect;
vect_show = vect;
vect_aim = vect;
anim_counter = 0;
anim_time = 0;
anim_time_counter = 0;
aim_is_end = true;
}
void sharpen()
{
init(vect_show);
}
void update(v3f vect_new, bool is_end_position=false, float update_interval=-1)
{
aim_is_end = is_end_position;
vect_old = vect_show;
vect_aim = vect_new;
if(update_interval > 0){
anim_time = update_interval;
} else {
if(anim_time < 0.001 || anim_time > 1.0)
anim_time = anim_time_counter;
else
anim_time = anim_time * 0.9 + anim_time_counter * 0.1;
}
anim_time_counter = 0;
anim_counter = 0;
}
void translate(f32 dtime)
{
anim_time_counter = anim_time_counter + dtime;
anim_counter = anim_counter + dtime;
v3f vect_move = vect_aim - vect_old;
f32 moveratio = 1.0;
if(anim_time > 0.001)
moveratio = anim_time_counter / anim_time;
// Move a bit less than should, to avoid oscillation
moveratio = moveratio * 0.8;
float move_end = 1.5;
if(aim_is_end)
move_end = 1.0;
if(moveratio > move_end)
moveratio = move_end;
vect_show = vect_old + vect_move * moveratio;
}
bool is_moving()
{
return ((anim_time_counter / anim_time) < 1.4);
}
};
void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill,
float txs, float tys, int col, int row);
#endif

181
src/content_cao_firefly.cpp Normal file
View File

@@ -0,0 +1,181 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content_cao.h"
/*
FireflyCAO
*/
class FireflyCAO : public ClientActiveObject
{
public:
FireflyCAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
m_node(NULL),
m_position(v3f(0,10*BS,0)),
m_yaw(0)
{
registerType(getType(), create);
};
~FireflyCAO()
{
}
inline u8 getType() const { return ACTIVEOBJECT_TYPE_FIREFLY; }
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
{
return new FireflyCAO(gamedef, env);
}
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
//video::IVideoDriver* driver = smgr->getVideoDriver();
scene::SMesh *mesh = new scene::SMesh();
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(0,0,0, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
video::S3DVertex(0,BS/2,0, 0,0,0, c, 0,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
//buf->getMaterial().setTexture(0, NULL);
buf->getMaterial().setTexture(0, tsrc->getTextureRaw("firefly.png"));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
// Set it to use the materials of the meshbuffers directly.
// This is needed for changing the texture in the future
m_node->setReadOnlyMaterials(true);
updateNodePos();
}
void removeFromScene()
{
if(m_node == NULL)
return;
m_node->remove();
m_node = NULL;
}
void updateLight(u8 light_at_pos)
{
if(m_node == NULL)
return;
u8 li = 255;
video::SColor color(255,li,li,li);
setMeshColor(m_node->getMesh(), color);
}
v3s16 getLightPosition()
{
return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
}
void updateNodePos()
{
if(m_node == NULL)
return;
//m_node->setPosition(m_position);
m_node->setPosition(pos_translator.vect_show);
v3f rot = m_node->getRotation();
rot.Y = 180.0 - m_yaw;
m_node->setRotation(rot);
}
void step(float dtime, ClientEnvironment *env)
{
pos_translator.translate(dtime);
updateNodePos();
}
void processMessage(const std::string &data)
{
//infostream<<"FireflyCAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
if(cmd == AO_Message_type::SetPosition)
{
// pos
m_position = readV3F1000(is);
pos_translator.update(m_position);
// yaw
m_yaw = readF1000(is);
updateNodePos();
}
}
void initialize(const std::string &data)
{
//infostream<<"FireflyCAO: Got init data"<<std::endl;
{
std::istringstream is(data, std::ios::binary);
// version
u8 version = readU8(is);
// check version
if(version != 0)
return;
// pos
m_position = readV3F1000(is);
pos_translator.init(m_position);
}
updateNodePos();
}
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return m_position;}
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
};
// Prototype
FireflyCAO proto_FireflyCAO(NULL, NULL);

239
src/content_cao_item.cpp Normal file
View File

@@ -0,0 +1,239 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content_cao.h"
#include "inventory.h"
/*
ItemCAO
*/
class ItemCAO : public ClientActiveObject
{
public:
ItemCAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.),
m_node(NULL),
m_position(v3f(0,10*BS,0))
{
if(!gamedef && !env)
{
ClientActiveObject::registerType(getType(), create);
}
}
~ItemCAO()
{
}
inline u8 getType() const
{ return ACTIVEOBJECT_TYPE_ITEM; }
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
{
return new ItemCAO(gamedef, env);
}
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
//video::IVideoDriver* driver = smgr->getVideoDriver();
scene::SMesh *mesh = new scene::SMesh();
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
/*video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/
video::S3DVertex(BS/3.,0,0, 0,0,0, c, 0,1),
video::S3DVertex(-BS/3.,0,0, 0,0,0, c, 1,1),
video::S3DVertex(-BS/3.,0+BS*2./3.,0, 0,0,0, c, 1,0),
video::S3DVertex(BS/3.,0+BS*2./3.,0, 0,0,0, c, 0,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
// Initialize with a generated placeholder texture
buf->getMaterial().setTexture(0, tsrc->getTextureRaw(""));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
// Set it to use the materials of the meshbuffers directly.
// This is needed for changing the texture in the future
m_node->setReadOnlyMaterials(true);
updateNodePos();
/*
Update image of node
*/
// Create an inventory item to see what is its image
std::istringstream is(m_inventorystring, std::ios_base::binary);
video::ITexture *texture = NULL;
try{
InventoryItem *item = NULL;
item = InventoryItem::deSerialize(is, m_gamedef);
infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
<<m_inventorystring<<"\" -> item="<<item
<<std::endl;
if(item)
{
texture = item->getImage();
delete item;
}
}
catch(SerializationError &e)
{
infostream<<"WARNING: "<<__FUNCTION_NAME
<<": error deSerializing inventorystring \""
<<m_inventorystring<<"\""<<std::endl;
}
// Set meshbuffer texture
buf->getMaterial().setTexture(0, texture);
}
void removeFromScene()
{
if(m_node == NULL)
return;
m_node->remove();
m_node = NULL;
}
void updateLight(u8 light_at_pos)
{
if(m_node == NULL)
return;
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
setMeshColor(m_node->getMesh(), color);
}
v3s16 getLightPosition()
{
return floatToInt(m_position, BS);
}
void updateNodePos()
{
if(m_node == NULL)
return;
m_node->setPosition(m_position);
}
void step(float dtime, ClientEnvironment *env)
{
if(m_node)
{
/*v3f rot = m_node->getRotation();
rot.Y += dtime * 120;
m_node->setRotation(rot);*/
LocalPlayer *player = env->getLocalPlayer();
assert(player);
v3f rot = m_node->getRotation();
rot.Y = 180.0 - (player->getYaw());
m_node->setRotation(rot);
}
}
void processMessage(const std::string &data)
{
//infostream<<"ItemCAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
if(cmd == AO_Message_type::SetPosition)
{
// pos
m_position = readV3F1000(is);
updateNodePos();
}
}
void initialize(const std::string &data)
{
infostream<<"ItemCAO: Got init data"<<std::endl;
{
std::istringstream is(data, std::ios::binary);
// version
u8 version = readU8(is);
// check version
if(version != 0)
return;
// pos
m_position = readV3F1000(is);
// inventorystring
m_inventorystring = deSerializeString(is);
}
updateNodePos();
/*
Set infotext to item name if item cannot be deserialized
*/
try{
InventoryItem *item = NULL;
item = InventoryItem::deSerialize(m_inventorystring, m_gamedef);
if(item){
if(!item->isKnown())
m_infotext = "Unknown item: '" + m_inventorystring + "'";
}
delete item;
}
catch(SerializationError &e)
{
m_infotext = "Unknown item: '" + m_inventorystring + "'";
}
}
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return m_position;}
std::string infoText()
{return m_infotext;}
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
std::string m_inventorystring;
std::string m_infotext;
};
// Prototype
ItemCAO proto_ItemCAO(NULL, NULL);

426
src/content_cao_lua.cpp Normal file
View File

@@ -0,0 +1,426 @@
/*
Minetest-c55
Copyright (C) 2010-2012 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 <list>
#include "content_cao.h"
#include "luaentity_common.h"
#include "clientlinkableobject.h"
class LuaEntityCAO : public ClientActiveObject, public ClientLinkableObject
{
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_meshnode;
scene::IBillboardSceneNode *m_spritenode;
v3f m_position;
v3f m_velocity;
v3f m_acceleration;
float m_yaw;
struct LuaEntityProperties *m_prop;
SmoothTranslator pos_translator;
// Spritesheet/animation stuff
v2f m_tx_size;
v2s16 m_tx_basepos;
bool m_tx_select_horiz_by_yawpitch;
int m_anim_frame;
int m_anim_num_frames;
float m_anim_framelength;
float m_anim_timer;
public:
inline u8 getType() const { return ACTIVEOBJECT_TYPE_LUAENTITY; }
inline core::aabbox3d<f32>* getSelectionBox()
{ return &m_selection_box; }
inline v3f getPosition()
{ return pos_translator.vect_show; }
LuaEntityCAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
m_meshnode(NULL),
m_spritenode(NULL),
m_position(v3f(0,10*BS,0)),
m_velocity(v3f(0,0,0)),
m_acceleration(v3f(0,0,0)),
m_yaw(0),
m_prop(new LuaEntityProperties),
m_tx_size(1,1),
m_tx_basepos(0,0),
m_tx_select_horiz_by_yawpitch(false),
m_anim_frame(0),
m_anim_num_frames(1),
m_anim_framelength(0.2),
m_anim_timer(0)
{
if(gamedef == NULL)
ClientActiveObject::registerType(LuaEntityCAO::getType(), LuaEntityCAO::create);
}
void initialize(const std::string &data)
{
infostream<<"LuaEntityCAO: Got init data"<<std::endl;
std::istringstream is(data, std::ios::binary);
// version
u8 version = readU8(is);
// check version
if(version != 0)
return;
// pos
m_position = readV3F1000(is);
// yaw
m_yaw = readF1000(is);
// properties
std::istringstream prop_is(deSerializeLongString(is), std::ios::binary);
m_prop->deSerialize(prop_is);
infostream<<"m_prop: "<<m_prop->dump()<<std::endl;
m_selection_box = m_prop->collisionbox;
m_selection_box.MinEdge *= BS;
m_selection_box.MaxEdge *= BS;
pos_translator.init(m_position);
m_tx_size.X = 1.0 / m_prop->spritediv.X;
m_tx_size.Y = 1.0 / m_prop->spritediv.Y;
m_tx_basepos.X = m_tx_size.X * m_prop->initial_sprite_basepos.X;
m_tx_basepos.Y = m_tx_size.Y * m_prop->initial_sprite_basepos.Y;
updateNodePos();
}
~LuaEntityCAO()
{
delete m_prop;
}
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
{
return new LuaEntityCAO(gamedef, env);
}
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_meshnode != NULL || m_spritenode != NULL)
return;
//video::IVideoDriver* driver = smgr->getVideoDriver();
if(m_prop->visual == "sprite"){
infostream<<"LuaEntityCAO::addToScene(): single_sprite"<<std::endl;
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);
m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
m_spritenode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
m_spritenode->setColor(video::SColor(255,0,0,0));
m_spritenode->setVisible(false); /* Set visible when brightness is known */
m_spritenode->setSize(m_prop->visual_size*BS);
{
const float txs = 1.0 / 1;
const float tys = 1.0 / 1;
setBillboardTextureMatrix(m_spritenode,
txs, tys, 0, 0);
}
} else if(m_prop->visual == "cube"){
infostream<<"LuaEntityCAO::addToScene(): cube"<<std::endl;
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
m_meshnode->setScale(v3f(1));
// Will be shown when we know the brightness
m_meshnode->setVisible(false);
} else if (m_prop->visual == "plant") {
infostream<<"LuaEntityCAO::addToScene(): plant"<<std::endl;
scene::IMesh *mesh = createPlantMesh(v3f(BS,BS,BS));
m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
m_meshnode->setScale(v3f(1));
// Will be shown when we know the brightness
m_meshnode->setVisible(false);
} else if (m_prop->visual == "cube_disorted") {
infostream<<"LuaEntityCAO::addToScene(): irregular_cube"<<std::endl;
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS), m_prop->collisionbox);
m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
m_meshnode->setScale(v3f(1));
// Will be shown when we know the brightness
m_meshnode->setVisible(false);
} else {
infostream<<"LuaEntityCAO::addToScene(): \""<<m_prop->visual
<<"\" not supported"<<std::endl;
}
updateTextures("");
updateNodePos();
}
void removeFromScene()
{
if(m_meshnode){
m_meshnode->remove();
m_meshnode = NULL;
}
if(m_spritenode){
m_spritenode->remove();
m_spritenode = NULL;
}
}
void updateLight(u8 light_at_pos)
{
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
if(m_meshnode){
setMeshColor(m_meshnode->getMesh(), color);
m_meshnode->setVisible(true);
}
if(m_spritenode){
m_spritenode->setColor(color);
m_spritenode->setVisible(true);
}
}
v3s16 getLightPosition()
{
return floatToInt(m_position, BS);
}
void updateNodePos()
{
if(m_meshnode){
m_meshnode->setPosition(pos_translator.vect_show);
}
if(m_spritenode){
m_spritenode->setPosition(pos_translator.vect_show);
}
}
void step(float dtime, ClientEnvironment *env)
{
//if liked movement is handled by parent entity
if(!this->isLinked()) {
if(m_prop->physical){
core::aabbox3d<f32> box = m_prop->collisionbox;
box.MinEdge *= BS;
box.MaxEdge *= BS;
collisionMoveResult moveresult;
f32 pos_max_d = BS*0.25; // Distance per iteration
v3f p_pos = m_position;
v3f p_velocity = m_velocity;
IGameDef *gamedef = env->getGameDef();
moveresult = collisionMovePrecise(&env->getMap(), gamedef,
pos_max_d, box, dtime, p_pos, p_velocity);
// Apply results
m_position = p_pos;
m_velocity = p_velocity;
bool is_end_position = moveresult.collides;
pos_translator.update(m_position, is_end_position, dtime);
pos_translator.translate(dtime);
updateNodePos();
m_velocity += dtime * m_acceleration;
} else {
m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
m_velocity += dtime * m_acceleration;
pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time);
pos_translator.translate(dtime);
updateNodePos();
}
}
stepLinkedObjects(this->m_position,dtime);
m_anim_timer += dtime;
if(m_anim_timer >= m_anim_framelength){
m_anim_timer -= m_anim_framelength;
m_anim_frame++;
if(m_anim_frame >= m_anim_num_frames)
m_anim_frame = 0;
}
updateTexturePos();
}
void updateTexturePos()
{
if(m_spritenode){
scene::ICameraSceneNode* camera =
m_spritenode->getSceneManager()->getActiveCamera();
if(!camera)
return;
v3f cam_to_entity = m_spritenode->getAbsolutePosition()
- camera->getAbsolutePosition();
cam_to_entity.normalize();
int row = m_tx_basepos.Y;
int col = m_tx_basepos.X;
if(m_tx_select_horiz_by_yawpitch)
{
if(cam_to_entity.Y > 0.75)
col += 5;
else if(cam_to_entity.Y < -0.75)
col += 4;
else{
float mob_dir = atan2(cam_to_entity.Z, cam_to_entity.X) / PI * 180.;
float dir = mob_dir - m_yaw;
dir = wrapDegrees_180(dir);
//infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
col += 2;
else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
col += 3;
else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
col += 0;
else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
col += 1;
else
col += 4;
}
}
// Animation goes downwards
row += m_anim_frame;
float txs = m_tx_size.X;
float tys = m_tx_size.Y;
setBillboardTextureMatrix(m_spritenode,
txs, tys, col, row);
}
}
void updateTextures(const std::string &mod)
{
ITextureSource *tsrc = m_gamedef->tsrc();
if(m_spritenode){
std::string texturestring = "unknown_block.png";
if(m_prop->textures.size() >= 1)
texturestring = m_prop->textures[0];
texturestring += mod;
m_spritenode->setMaterialTexture(0,
tsrc->getTextureRaw(texturestring));
}
if(m_meshnode){
for (u32 i = 0; i < 6; ++i)
{
std::string texturestring = "unknown_block.png";
if(m_prop->textures.size() > i)
texturestring = m_prop->textures[i];
texturestring += mod;
AtlasPointer ap = tsrc->getTexture(texturestring);
// Get the tile texture and atlas transformation
video::ITexture* atlas = ap.atlas;
v2f pos = ap.pos;
v2f size = ap.size;
// Set material flags and texture
video::SMaterial& material = m_meshnode->getMaterial(i);
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
material.setTexture(0, atlas);
material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
}
}
}
void processMessage(const std::string &data)
{
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
if(cmd == AO_Message_type::SetPosition) // update position
{
// do_interpolate
bool do_interpolate = readU8(is);
// pos
m_position = readV3F1000(is);
// velocity
m_velocity = readV3F1000(is);
// acceleration
m_acceleration = readV3F1000(is);
// yaw
m_yaw = readF1000(is);
// is_end_position (for interpolation)
bool is_end_position = readU8(is);
// update_interval
float update_interval = readF1000(is);
if(do_interpolate){
if(!m_prop->physical)
pos_translator.update(m_position, is_end_position, update_interval);
} else {
pos_translator.init(m_position);
}
updateNodePos();
}
else if(cmd == AO_Message_type::SetTextureMod) // set texture modification
{
std::string mod = deSerializeString(is);
updateTextures(mod);
}
else if(cmd == AO_Message_type::SetSprite) // set sprite
{
v2s16 p = readV2S16(is);
int num_frames = readU16(is);
float framelength = readF1000(is);
bool select_horiz_by_yawpitch = readU8(is);
m_tx_basepos = p;
m_anim_num_frames = num_frames;
m_anim_framelength = framelength;
m_tx_select_horiz_by_yawpitch = select_horiz_by_yawpitch;
updateTexturePos();
}
else if (handleLinkUnlinkMessages(cmd,&is,this->m_env))
{
//Link unlink already done in handleLinkUnlinkMessages!
}
}
void setPosition(v3f toset, float dtime){
if (this->isLinked()) {
this->m_position = toset + this->m_linkOffset;
pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time);
pos_translator.translate(dtime);
updateNodePos();
}
}
void updateLinkState(bool value) {}
};
// Prototype
LuaEntityCAO proto_LuaEntityCAO(NULL, NULL);

464
src/content_cao_mobv2.cpp Normal file
View File

@@ -0,0 +1,464 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content_cao.h"
/*
MobV2CAO
*/
class MobV2CAO : public ClientActiveObject
{
public:
MobV2CAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-0.4*BS,-0.4*BS,-0.4*BS, 0.4*BS,0.8*BS,0.4*BS),
m_node(NULL),
m_position(v3f(0,10*BS,0)),
m_yaw(0),
m_walking(false),
m_walking_unset_timer(0),
m_walk_timer(0),
m_walk_frame(0),
m_damage_visual_timer(0),
m_last_light(0),
m_shooting(0),
m_shooting_unset_timer(0),
m_sprite_size(BS,BS),
m_sprite_y(0),
m_bright_shooting(false),
m_lock_full_brightness(false),
m_player_hit_timer(0)
{
ClientActiveObject::registerType(getType(), create);
m_properties = new Settings;
}
~MobV2CAO()
{
delete m_properties;
}
inline u8 getType() const { return ACTIVEOBJECT_TYPE_MOBV2; }
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
{
return new MobV2CAO(gamedef, env);
}
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
/*infostream<<"MobV2CAO::addToScene using texture_name="<<
m_texture_name<<std::endl;*/
std::string texture_string = m_texture_name +
"^[makealpha:128,0,0^[makealpha:128,128,0";
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);
bill->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
bill->setMaterialFlag(video::EMF_FOG_ENABLE, true);
bill->setColor(video::SColor(255,0,0,0));
bill->setVisible(false); /* Set visible when brightness is known */
bill->setSize(m_sprite_size);
if(m_sprite_type == "humanoid_1"){
const float txp = 1./192;
const float txs = txp*32;
const float typ = 1./240;
const float tys = typ*48;
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;
setBillboardTextureMatrix(bill, txs, tys, 0, 0);
} else {
infostream<<"MobV2CAO: Unknown sprite type \""<<m_sprite_type<<"\""
<<std::endl;
}
m_node = bill;
updateNodePos();
}
void removeFromScene()
{
if(m_node == NULL)
return;
m_node->remove();
m_node = NULL;
}
void updateLight(u8 light_at_pos)
{
if(m_lock_full_brightness)
light_at_pos = 15;
m_last_light = light_at_pos;
if(m_node == NULL)
return;
if(m_damage_visual_timer > 0)
return;
if(m_shooting && m_bright_shooting)
return;
/*if(light_at_pos <= 2){
m_node->setVisible(false);
return;
}*/
m_node->setVisible(true);
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
m_node->setColor(color);
}
v3s16 getLightPosition()
{
return floatToInt(m_position+v3f(0,0,0), BS);
}
void updateNodePos()
{
if(m_node == NULL)
return;
m_node->setPosition(pos_translator.vect_show + v3f(0,m_sprite_y,0));
}
void step(float dtime, ClientEnvironment *env)
{
scene::IBillboardSceneNode *bill = m_node;
if(!bill)
return;
pos_translator.translate(dtime);
if(m_sprite_type == "humanoid_1"){
scene::ICameraSceneNode* camera = m_node->getSceneManager()->getActiveCamera();
if(!camera)
return;
v3f cam_to_mob = m_node->getAbsolutePosition() - camera->getAbsolutePosition();
cam_to_mob.normalize();
int col = 0;
if(cam_to_mob.Y > 0.75)
col = 5;
else if(cam_to_mob.Y < -0.75)
col = 4;
else{
float mob_dir = atan2(cam_to_mob.Z, cam_to_mob.X) / PI * 180.;
float dir = mob_dir - m_yaw;
dir = wrapDegrees_180(dir);
//infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
col = 2;
else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
col = 3;
else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
col = 0;
else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
col = 1;
else
col = 4;
}
int row = 0;
if(m_shooting){
row = 3;
} else if(m_walking){
m_walk_timer += dtime;
if(m_walk_timer >= 0.5){
m_walk_frame = (m_walk_frame + 1) % 2;
m_walk_timer = 0;
}
if(m_walk_frame == 0)
row = 1;
else
row = 2;
}
const float txp = 1./192;
const float txs = txp*32;
const float typ = 1./240;
const float tys = typ*48;
setBillboardTextureMatrix(bill, txs, tys, col, row);
} else if(m_sprite_type == "simple"){
m_walk_timer += dtime;
if(m_walk_timer >= m_simple_anim_frametime){
m_walk_frame = (m_walk_frame + 1) % m_simple_anim_frames;
m_walk_timer = 0;
}
int col = 0;
int row = m_walk_frame;
const float txs = 1.0;
const float tys = 1.0 / m_simple_anim_frames;
setBillboardTextureMatrix(bill, txs, tys, col, row);
} else {
infostream<<"MobV2CAO::step(): Unknown sprite type \""
<<m_sprite_type<<"\""<<std::endl;
}
updateNodePos();
/* Damage local player */
if(m_player_hit_damage && m_player_hit_timer <= 0.0){
LocalPlayer *player = env->getLocalPlayer();
assert(player);
v3f playerpos = player->getPosition();
v2f playerpos_2d(playerpos.X,playerpos.Z);
v2f objectpos_2d(m_position.X,m_position.Z);
if(fabs(m_position.Y - playerpos.Y) < m_player_hit_distance*BS &&
objectpos_2d.getDistanceFrom(playerpos_2d) < m_player_hit_distance*BS)
{
env->damageLocalPlayer(m_player_hit_damage);
m_player_hit_timer = m_player_hit_interval;
}
}
/* Run timers */
m_player_hit_timer -= dtime;
if(m_damage_visual_timer >= 0){
m_damage_visual_timer -= dtime;
if(m_damage_visual_timer <= 0){
infostream<<"id="<<m_id<<" damage visual ended"<<std::endl;
}
}
m_walking_unset_timer += dtime;
if(m_walking_unset_timer >= 1.0){
m_walking = false;
}
m_shooting_unset_timer -= dtime;
if(m_shooting_unset_timer <= 0.0){
if(m_bright_shooting){
u8 li = decode_light(m_last_light);
video::SColor color(255,li,li,li);
bill->setColor(color);
m_bright_shooting = false;
}
m_shooting = false;
}
}
void processMessage(const std::string &data)
{
//infostream<<"MobV2CAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
// Move
if(cmd == AO_Message_type::SetPosition)
{
// pos
m_position = readV3F1000(is);
pos_translator.update(m_position);
// yaw
m_yaw = readF1000(is);
m_walking = true;
m_walking_unset_timer = 0;
updateNodePos();
}
// Damage
else if(cmd == AO_Message_type::TakeDamage)
{
//u16 damage = readU16(is);
/*u8 li = decode_light(m_last_light);
if(li >= 100)
li = 30;
else
li = 255;*/
/*video::SColor color(255,255,0,0);
m_node->setColor(color);
m_damage_visual_timer = 0.2;*/
}
// Trigger shooting
else if(cmd == AO_Message_type::Shoot)
{
// length
m_shooting_unset_timer = readF1000(is);
// bright?
m_bright_shooting = readU8(is);
if(m_bright_shooting){
u8 li = 255;
video::SColor color(255,li,li,li);
m_node->setColor(color);
}
m_shooting = true;
}
}
void initialize(const std::string &data)
{
//infostream<<"MobV2CAO: Got init data"<<std::endl;
{
std::istringstream is(data, std::ios::binary);
// version
u8 version = readU8(is);
// check version
if(version != 0){
infostream<<__FUNCTION_NAME<<": Invalid version"<<std::endl;
return;
}
std::ostringstream tmp_os(std::ios::binary);
decompressZlib(is, tmp_os);
std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
m_properties->parseConfigLines(tmp_is, "MobArgsEnd");
infostream<<"MobV2CAO::initialize(): got properties:"<<std::endl;
m_properties->writeLines(infostream);
m_properties->setDefault("looks", "dummy_default");
m_properties->setDefault("yaw", "0");
m_properties->setDefault("pos", "(0,0,0)");
m_properties->setDefault("player_hit_damage", "0");
m_properties->setDefault("player_hit_distance", "1.5");
m_properties->setDefault("player_hit_interval", "1.5");
setLooks(m_properties->get("looks"));
m_yaw = m_properties->getFloat("yaw");
m_position = m_properties->getV3F("pos");
m_player_hit_damage = m_properties->getS32("player_hit_damage");
m_player_hit_distance = m_properties->getFloat("player_hit_distance");
m_player_hit_interval = m_properties->getFloat("player_hit_interval");
pos_translator.init(m_position);
}
updateNodePos();
}
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return pos_translator.vect_show;}
bool directReportPunch(const std::string &toolname, v3f dir)
{
video::SColor color(255,255,0,0);
m_node->setColor(color);
m_damage_visual_timer = 0.05;
m_position += dir * BS;
pos_translator.sharpen();
pos_translator.update(m_position);
updateNodePos();
return false;
}
private:
void setLooks(const std::string &looks)
{
v2f selection_size = v2f(0.4, 0.4) * BS;
float selection_y = 0 * BS;
if(looks == "dungeon_master"){
m_texture_name = "dungeon_master.png";
m_sprite_type = "humanoid_1";
m_sprite_size = v2f(2, 3) * BS;
m_sprite_y = 0.85 * BS;
selection_size = v2f(0.4, 2.6) * BS;
selection_y = -0.4 * BS;
}
else if(looks == "fireball"){
m_texture_name = "fireball.png";
m_sprite_type = "simple";
m_sprite_size = v2f(1, 1) * BS;
m_simple_anim_frames = 3;
m_simple_anim_frametime = 0.1;
m_lock_full_brightness = true;
}
else{
m_texture_name = "stone.png";
m_sprite_type = "simple";
m_sprite_size = v2f(1, 1) * BS;
m_simple_anim_frames = 3;
m_simple_anim_frametime = 0.333;
selection_size = v2f(0.4, 0.4) * BS;
selection_y = 0 * BS;
}
m_selection_box = core::aabbox3d<f32>(
-selection_size.X, selection_y, -selection_size.X,
selection_size.X, selection_y+selection_size.Y,
selection_size.X);
}
IntervalLimiter m_attack_interval;
core::aabbox3d<f32> m_selection_box;
scene::IBillboardSceneNode *m_node;
v3f m_position;
std::string m_texture_name;
float m_yaw;
SmoothTranslator pos_translator;
bool m_walking;
float m_walking_unset_timer;
float m_walk_timer;
int m_walk_frame;
float m_damage_visual_timer;
u8 m_last_light;
bool m_shooting;
float m_shooting_unset_timer;
v2f m_sprite_size;
float m_sprite_y;
bool m_bright_shooting;
std::string m_sprite_type;
int m_simple_anim_frames;
float m_simple_anim_frametime;
bool m_lock_full_brightness;
int m_player_hit_damage;
float m_player_hit_distance;
float m_player_hit_interval;
float m_player_hit_timer;
Settings *m_properties;
};
// Prototype
MobV2CAO proto_MobV2CAO(NULL, NULL);

283
src/content_cao_oerkki1.cpp Normal file
View File

@@ -0,0 +1,283 @@
/*
Minetest-c55
Copyright (C) 2010-2012 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 "inventory.h"
#include "content_cao.h"
/*
Oerkki1CAO
*/
class Oerkki1CAO : public ClientActiveObject
{
public:
Oerkki1CAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.,BS/3.),
m_node(NULL),
m_position(v3f(0,10*BS,0)),
m_yaw(0),
m_damage_visual_timer(0),
m_damage_texture_enabled(false)
{
ClientActiveObject::registerType(getType(), create);
}
~Oerkki1CAO()
{
}
inline u8 getType() const { return ACTIVEOBJECT_TYPE_OERKKI1; }
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
{
return new Oerkki1CAO(gamedef, env);
}
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
//video::IVideoDriver* driver = smgr->getVideoDriver();
scene::SMesh *mesh = new scene::SMesh();
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2-BS,0,0, 0,0,0, c, 0,1),
video::S3DVertex(BS/2+BS,0,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2+BS,BS*2,0, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2-BS,BS*2,0, 0,0,0, c, 0,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
//buf->getMaterial().setTexture(0, NULL);
buf->getMaterial().setTexture(0, tsrc->getTextureRaw("oerkki1.png"));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
// Set it to use the materials of the meshbuffers directly.
// This is needed for changing the texture in the future
m_node->setReadOnlyMaterials(true);
updateNodePos();
}
void removeFromScene()
{
if(m_node == NULL)
return;
m_node->remove();
m_node = NULL;
}
void updateLight(u8 light_at_pos)
{
if(m_node == NULL)
return;
if(light_at_pos <= 2)
{
m_node->setVisible(false);
return;
}
m_node->setVisible(true);
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
setMeshColor(m_node->getMesh(), color);
}
v3s16 getLightPosition()
{
return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
}
void updateNodePos()
{
if(m_node == NULL)
return;
//m_node->setPosition(m_position);
m_node->setPosition(pos_translator.vect_show);
v3f rot = m_node->getRotation();
rot.Y = 180.0 - m_yaw + 90.0;
m_node->setRotation(rot);
}
void step(float dtime, ClientEnvironment *env)
{
ITextureSource *tsrc = m_gamedef->tsrc();
pos_translator.translate(dtime);
updateNodePos();
LocalPlayer *player = env->getLocalPlayer();
assert(player);
v3f playerpos = player->getPosition();
v2f playerpos_2d(playerpos.X,playerpos.Z);
v2f objectpos_2d(m_position.X,m_position.Z);
if(fabs(m_position.Y - playerpos.Y) < 1.5*BS &&
objectpos_2d.getDistanceFrom(playerpos_2d) < 1.5*BS)
{
if(m_attack_interval.step(dtime, 0.5))
{
env->damageLocalPlayer(2);
}
}
if(m_damage_visual_timer > 0)
{
if(!m_damage_texture_enabled)
{
// Enable damage texture
if(m_node)
{
/*video::IVideoDriver* driver =
m_node->getSceneManager()->getVideoDriver();*/
scene::IMesh *mesh = m_node->getMesh();
if(mesh == NULL)
return;
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
buf->getMaterial().setTexture(0,
tsrc->getTextureRaw("oerkki1_damaged.png"));
}
}
m_damage_texture_enabled = true;
}
m_damage_visual_timer -= dtime;
}
else
{
if(m_damage_texture_enabled)
{
// Disable damage texture
if(m_node)
{
/*video::IVideoDriver* driver =
m_node->getSceneManager()->getVideoDriver();*/
scene::IMesh *mesh = m_node->getMesh();
if(mesh == NULL)
return;
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
buf->getMaterial().setTexture(0,
tsrc->getTextureRaw("oerkki1.png"));
}
}
m_damage_texture_enabled = false;
}
}
}
void processMessage(const std::string &data)
{
//infostream<<"Oerkki1CAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
if(cmd == AO_Message_type::SetPosition)
{
// pos
m_position = readV3F1000(is);
pos_translator.update(m_position);
// yaw
m_yaw = readF1000(is);
updateNodePos();
}
else if(cmd == AO_Message_type::TakeDamage)
{
//u16 damage = readU8(is);
m_damage_visual_timer = 1.0;
}
}
void initialize(const std::string &data)
{
//infostream<<"Oerkki1CAO: Got init data"<<std::endl;
{
std::istringstream is(data, std::ios::binary);
// version
u8 version = readU8(is);
// check version
if(version != 0)
return;
// pos
m_position = readV3F1000(is);
pos_translator.init(m_position);
}
updateNodePos();
}
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return pos_translator.vect_show;}
bool directReportPunch(const std::string &toolname, v3f dir)
{
m_damage_visual_timer = 1.0;
m_position += dir * BS;
pos_translator.sharpen();
pos_translator.update(m_position);
updateNodePos();
return false;
}
private:
IntervalLimiter m_attack_interval;
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
float m_damage_visual_timer;
bool m_damage_texture_enabled;
};
// Prototype
Oerkki1CAO proto_Oerkki1CAO(NULL, NULL);

315
src/content_cao_player.cpp Normal file
View File

@@ -0,0 +1,315 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content_cao.h"
#include "clientlinkableobject.h"
/*
PlayerCAO
*/
class PlayerCAO : public ClientActiveObject, public ClientLinkableObject
{
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
scene::ITextSceneNode* m_text;
std::string m_name;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
bool m_is_local_player;
LocalPlayer *m_local_player;
float m_damage_visual_timer;
public:
PlayerCAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.0,BS/3.),
m_node(NULL),
m_text(NULL),
m_position(v3f(0,10*BS,0)),
m_yaw(0),
m_is_local_player(false),
m_local_player(NULL),
m_damage_visual_timer(0)
{
if(gamedef == NULL)
ClientActiveObject::registerType(getType(), create);
}
void initialize(const std::string &data)
{
infostream<<"PlayerCAO: Got init data"<<std::endl;
std::istringstream is(data, std::ios::binary);
// version
u8 version = readU8(is);
// check version
if(version != 0)
return;
// name
m_name = deSerializeString(is);
// pos
m_position = readV3F1000(is);
// yaw
m_yaw = readF1000(is);
pos_translator.init(m_position);
Player *player = m_env->getPlayer(m_name.c_str());
if(player && player->isLocal()){
m_is_local_player = true;
m_local_player = (LocalPlayer*)player;
}
}
~PlayerCAO()
{
if(m_node)
m_node->remove();
}
inline u8 getType() const { return ACTIVEOBJECT_TYPE_PLAYER; }
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
{
return new PlayerCAO(gamedef, env);
}
core::aabbox3d<f32>* getSelectionBox()
{
if(m_is_local_player)
return NULL;
return &m_selection_box;
}
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
if(m_is_local_player)
return;
//video::IVideoDriver* driver = smgr->getVideoDriver();
gui::IGUIEnvironment* gui = irr->getGUIEnvironment();
scene::SMesh *mesh = new scene::SMesh();
{ // Front
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
{ // Back
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
// Set it to use the materials of the meshbuffers directly.
// This is needed for changing the texture in the future
m_node->setReadOnlyMaterials(true);
updateNodePos();
// Add a text node for showing the name
std::wstring wname = narrow_to_wide(m_name);
m_text = smgr->addTextSceneNode(gui->getBuiltInFont(),
wname.c_str(), video::SColor(255,255,255,255), m_node);
m_text->setPosition(v3f(0, (f32)BS*2.1, 0));
updateTextures("");
updateNodePos();
}
void removeFromScene()
{
if(m_node == NULL)
return;
m_node->remove();
m_node = NULL;
}
void updateLight(u8 light_at_pos)
{
if(m_node == NULL)
return;
m_node->setVisible(true);
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
setMeshColor(m_node->getMesh(), color);
}
v3s16 getLightPosition()
{
return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
}
void updateNodePos()
{
if(m_node == NULL)
return;
m_node->setPosition(pos_translator.vect_show);
v3f rot = m_node->getRotation();
rot.Y = -m_yaw;
m_node->setRotation(rot);
}
void step(float dtime, ClientEnvironment *env)
{
if(!isLinked()) {
pos_translator.translate(dtime);
updateNodePos();
}
if(m_damage_visual_timer > 0){
m_damage_visual_timer -= dtime;
if(m_damage_visual_timer <= 0){
updateTextures("");
}
}
}
void processMessage(const std::string &data)
{
//infostream<<"PlayerCAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
if(cmd == AO_Message_type::SetPosition) // update position
{
// pos
m_position = readV3F1000(is);
// yaw
m_yaw = readF1000(is);
pos_translator.update(m_position, false);
updateNodePos();
}
else if(cmd == AO_Message_type::Punched) // punched
{
// damage
s16 damage = readS16(is);
if(m_is_local_player)
m_env->damageLocalPlayer(damage, false);
m_damage_visual_timer = 0.5;
updateTextures("^[brighten");
}
else if (handleLinkUnlinkMessages(cmd,&is,this->m_env))
{
//Link unlink already done in handleLinkUnlinkMessages!
}
}
void updateTextures(const std::string &mod)
{
if(!m_node)
return;
ITextureSource *tsrc = m_gamedef->tsrc();
scene::IMesh *mesh = m_node->getMesh();
if(mesh){
{
std::string tname = "player.png";
tname += mod;
scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
buf->getMaterial().setTexture(0,
tsrc->getTextureRaw(tname));
}
{
std::string tname = "player_back.png";
tname += mod;
scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
buf->getMaterial().setTexture(0,
tsrc->getTextureRaw(tname));
}
}
}
void setPosition(v3f toset, float dtime){
if (isLinked()) {
this->m_position = toset + this->m_linkOffset;
pos_translator.update(this->m_position,false);
updateNodePos();
if(m_is_local_player) {
m_local_player->setPosition(this->m_position);
}
}
else {
errorstream<<"Got linked position update but not linked"<< std::endl;
}
}
void updateLinkState(bool value) {
if(m_is_local_player) {
m_local_player->Link(value);
}
}
inline v3f getPosition() { return m_position; }
};
// Prototype
PlayerCAO proto_PlayerCAO(NULL, NULL);

183
src/content_cao_rat.cpp Normal file
View File

@@ -0,0 +1,183 @@
/*
Minetest-c55
Copyright (C) 2010-2012 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 "inventory.h"
#include "content_cao.h"
/*
RatCAO
*/
class RatCAO : public ClientActiveObject
{
public:
RatCAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
m_node(NULL),
m_position(v3f(0,10*BS,0)),
m_yaw(0)
{
ClientActiveObject::registerType(getType(), create);
}
~RatCAO()
{
}
inline u8 getType() const { return ACTIVEOBJECT_TYPE_RAT; }
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
{
return new RatCAO(gamedef, env);
}
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
//video::IVideoDriver* driver = smgr->getVideoDriver();
scene::SMesh *mesh = new scene::SMesh();
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
//buf->getMaterial().setTexture(0, NULL);
buf->getMaterial().setTexture(0, tsrc->getTextureRaw("rat.png"));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
// Set it to use the materials of the meshbuffers directly.
// This is needed for changing the texture in the future
m_node->setReadOnlyMaterials(true);
updateNodePos();
}
void removeFromScene()
{
if(m_node == NULL)
return;
m_node->remove();
m_node = NULL;
}
void updateLight(u8 light_at_pos)
{
if(m_node == NULL)
return;
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
setMeshColor(m_node->getMesh(), color);
}
v3s16 getLightPosition()
{
return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
}
void updateNodePos()
{
if(m_node == NULL)
return;
//m_node->setPosition(m_position);
m_node->setPosition(pos_translator.vect_show);
v3f rot = m_node->getRotation();
rot.Y = 180.0 - m_yaw;
m_node->setRotation(rot);
}
void step(float dtime, ClientEnvironment *env)
{
pos_translator.translate(dtime);
updateNodePos();
}
void processMessage(const std::string &data)
{
//infostream<<"RatCAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
if(cmd == AO_Message_type::SetPosition)
{
// pos
m_position = readV3F1000(is);
pos_translator.update(m_position);
// yaw
m_yaw = readF1000(is);
updateNodePos();
}
}
void initialize(const std::string &data)
{
//infostream<<"RatCAO: Got init data"<<std::endl;
{
std::istringstream is(data, std::ios::binary);
// version
u8 version = readU8(is);
// check version
if(version != 0)
return;
// pos
m_position = readV3F1000(is);
pos_translator.init(m_position);
}
updateNodePos();
}
core::aabbox3d<f32>* getSelectionBox()
{return &m_selection_box;}
v3f getPosition()
{return pos_translator.vect_show;}
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
};
// Prototype
RatCAO proto_RatCAO(NULL, NULL);

144
src/content_cao_test.cpp Normal file
View File

@@ -0,0 +1,144 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content_cao.h"
/*
TestCAO
*/
class TestCAO : public ClientActiveObject
{
public:
TestCAO(IGameDef *gamedef, ClientEnvironment *env):
ClientActiveObject(0, gamedef, env),
m_node(NULL),
m_position(v3f(0,10*BS,0))
{
ClientActiveObject::registerType(getType(), create);
}
~TestCAO()
{
}
static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
{
return new TestCAO(gamedef, env);
}
inline u8 getType() const
{ return ACTIVEOBJECT_TYPE_TEST; }
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr)
{
if(m_node != NULL)
return;
//video::IVideoDriver* driver = smgr->getVideoDriver();
scene::SMesh *mesh = new scene::SMesh();
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
buf->getMaterial().setTexture(0, tsrc->getTextureRaw("rat.png"));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
updateNodePos();
}
void removeFromScene()
{
if(m_node == NULL)
return;
m_node->remove();
m_node = NULL;
}
void updateLight(u8 light_at_pos)
{
}
v3s16 getLightPosition()
{
return floatToInt(m_position, BS);
}
void updateNodePos()
{
if(m_node == NULL)
return;
m_node->setPosition(m_position);
//m_node->setRotation(v3f(0, 45, 0));
}
void step(float dtime, ClientEnvironment *env)
{
if(m_node)
{
v3f rot = m_node->getRotation();
//infostream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
rot.Y += dtime * 180;
m_node->setRotation(rot);
}
}
void processMessage(const std::string &data)
{
infostream<<"TestCAO: Got data: "<<data<<std::endl;
std::istringstream is(data, std::ios::binary);
u16 cmd;
is>>cmd;
if(cmd == AO_Message_type::SetPosition)
{
v3f newpos;
is>>newpos.X;
is>>newpos.Y;
is>>newpos.Z;
m_position = newpos;
updateNodePos();
}
}
private:
scene::IMeshSceneNode *m_node;
v3f m_position;
};
// Prototype
TestCAO proto_TestCAO(NULL, NULL);

View File

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

View File

@@ -20,17 +20,27 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef CONTENT_OBJECT_HEADER
#define CONTENT_OBJECT_HEADER
#define ACTIVEOBJECT_TYPE_TEST 1
#define ACTIVEOBJECT_TYPE_ITEM 2
#define ACTIVEOBJECT_TYPE_RAT 3
#define ACTIVEOBJECT_TYPE_OERKKI1 4
#define ACTIVEOBJECT_TYPE_FIREFLY 5
#define ACTIVEOBJECT_TYPE_MOBV2 6
#define ACTIVEOBJECT_TYPE_LUAENTITY 7
#define ACTIVEOBJECT_TYPE_TEST 0x01
#define ACTIVEOBJECT_TYPE_ITEM 0x02
#define ACTIVEOBJECT_TYPE_RAT 0x03
#define ACTIVEOBJECT_TYPE_OERKKI1 0x04
#define ACTIVEOBJECT_TYPE_FIREFLY 0x05
#define ACTIVEOBJECT_TYPE_MOBV2 0x06
#define ACTIVEOBJECT_TYPE_LUAENTITY 0x07
// Special type, not stored as a static object
#define ACTIVEOBJECT_TYPE_PLAYER 100
#define ACTIVEOBJECT_TYPE_PLAYER 0x64
struct AO_Message_type {
static const u8 SetPosition = 0x00;
static const u8 SetTextureMod = 0x01;
static const u8 SetSprite = 0x02;
static const u8 Punched = 0x03;
static const u8 TakeDamage = 0x04;
static const u8 Shoot = 0x05;
static const u8 Link = 0x06;
static const u8 UnLink = 0x07;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -22,219 +22,25 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverobject.h"
#include "content_object.h"
class TestSAO : public ServerActiveObject
{
public:
TestSAO(ServerEnvironment *env, v3f pos);
u8 getType() const
{return ACTIVEOBJECT_TYPE_TEST;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
private:
float m_timer1;
float m_age;
};
class ItemSAO : public ServerActiveObject
{
public:
ItemSAO(ServerEnvironment *env, v3f pos,
const std::string inventorystring);
u8 getType() const
{return ACTIVEOBJECT_TYPE_ITEM;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
InventoryItem* createInventoryItem();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
float getMinimumSavedMovement(){ return 0.1*BS; }
private:
std::string m_inventorystring;
v3f m_speed_f;
v3f m_last_sent_position;
IntervalLimiter m_move_interval;
};
class RatSAO : public ServerActiveObject
{
public:
RatSAO(ServerEnvironment *env, v3f pos);
u8 getType() const
{return ACTIVEOBJECT_TYPE_RAT;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
private:
bool m_is_active;
IntervalLimiter m_inactive_interval;
v3f m_speed_f;
v3f m_oldpos;
v3f m_last_sent_position;
float m_yaw;
float m_counter1;
float m_counter2;
float m_age;
bool m_touching_ground;
};
class Oerkki1SAO : public ServerActiveObject
{
public:
Oerkki1SAO(ServerEnvironment *env, v3f pos);
u8 getType() const
{return ACTIVEOBJECT_TYPE_OERKKI1;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
bool isPeaceful(){return false;}
private:
void doDamage(u16 d);
bool m_is_active;
IntervalLimiter m_inactive_interval;
v3f m_speed_f;
v3f m_oldpos;
v3f m_last_sent_position;
float m_yaw;
float m_counter1;
float m_counter2;
float m_age;
bool m_touching_ground;
u8 m_hp;
float m_after_jump_timer;
};
class FireflySAO : public ServerActiveObject
{
public:
FireflySAO(ServerEnvironment *env, v3f pos);
u8 getType() const
{return ACTIVEOBJECT_TYPE_FIREFLY;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
private:
bool m_is_active;
IntervalLimiter m_inactive_interval;
v3f m_speed_f;
v3f m_oldpos;
v3f m_last_sent_position;
float m_yaw;
float m_counter1;
float m_counter2;
float m_age;
bool m_touching_ground;
};
#include "collision.h"
#include "environment.h"
#include "settings.h"
#include "main.h" // For g_profiler
#include "profiler.h"
#include "serialization.h" // For compressZlib
#include "materials.h" // For MaterialProperties
#include "tooldef.h" // ToolDiggingProperties
class Settings;
class MobV2SAO : public ServerActiveObject
{
public:
MobV2SAO(ServerEnvironment *env, v3f pos,
Settings *init_properties);
virtual ~MobV2SAO();
u8 getType() const
{return ACTIVEOBJECT_TYPE_MOBV2;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
std::string getStaticData();
std::string getClientInitializationData();
void step(float dtime, bool send_recommended);
void punch(ServerActiveObject *puncher, float time_from_last_punch);
bool isPeaceful();
private:
void sendPosition();
void setPropertyDefaults();
void readProperties();
void updateProperties();
void doDamage(u16 d);
std::string m_move_type;
v3f m_speed;
v3f m_last_sent_position;
v3f m_oldpos;
float m_yaw;
float m_counter1;
float m_counter2;
float m_age;
bool m_touching_ground;
int m_hp;
bool m_walk_around;
float m_walk_around_timer;
bool m_next_pos_exists;
v3s16 m_next_pos_i;
float m_shoot_reload_timer;
bool m_shooting;
float m_shooting_timer;
float m_die_age;
v2f m_size;
bool m_falling;
float m_disturb_timer;
std::string m_disturbing_player;
float m_random_disturb_timer;
float m_shoot_y;
Settings *m_properties;
};
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
struct LuaEntityProperties;
class LuaEntitySAO : public ServerActiveObject
{
public:
LuaEntitySAO(ServerEnvironment *env, v3f pos,
const std::string &name, const std::string &state);
~LuaEntitySAO();
u8 getType() const
{return ACTIVEOBJECT_TYPE_LUAENTITY;}
virtual void addedToEnvironment();
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
void rightClick(ServerActiveObject *clicker);
void setPos(v3f pos);
void moveTo(v3f pos, bool continuous);
float getMinimumSavedMovement();
/* LuaEntitySAO-specific */
void setVelocity(v3f velocity);
void setAcceleration(v3f acceleration);
v3f getAcceleration();
void setTextureMod(const std::string &mod);
void setSprite(v2s16 p, int num_frames, float framelength,
bool select_horiz_by_yawpitch);
private:
void sendPosition(bool do_interpolate, bool is_movement_end);
std::string m_init_name;
std::string m_init_state;
bool m_registered;
struct LuaEntityProperties *m_prop;
v3f m_velocity;
v3f m_acceleration;
float m_yaw;
float m_last_sent_yaw;
v3f m_last_sent_position;
v3f m_last_sent_velocity;
float m_last_sent_position_timer;
float m_last_sent_move_precision;
};
void accelerate_xz(v3f &speed, v3f target_speed, f32 max_increase);
bool checkFreePosition(Map *map, v3s16 p0, v3s16 size);
bool checkWalkablePosition(Map *map, v3s16 p0);
bool checkFreeAndWalkablePosition(Map *map, v3s16 p0, v3s16 size);
void get_random_u32_array(u32 a[], u32 len);
void explodeSquare(Map *map, v3s16 p0, v3s16 size);
#endif

193
src/content_sao_firefly.cpp Normal file
View File

@@ -0,0 +1,193 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content_sao_firefly.h"
/*
FireflySAO
*/
FireflySAO::FireflySAO(ServerEnvironment *env, v3f pos):
ServerActiveObject(env, pos),
m_is_active(false),
m_speed_f(0,0,0)
{
ServerActiveObject::registerType(getType(), create);
m_oldpos = v3f(0,0,0);
m_last_sent_position = v3f(0,0,0);
m_yaw = 0;
m_counter1 = 0;
m_counter2 = 0;
m_age = 0;
m_touching_ground = false;
}
ServerActiveObject* FireflySAO::create(ServerEnvironment *env, v3f pos,
const std::string &data)
{
std::istringstream is(data, std::ios::binary);
char buf[1];
// read version
is.read(buf, 1);
u8 version = buf[0];
// check if version is supported
if(version != 0)
return NULL;
return new FireflySAO(env, pos);
}
void FireflySAO::step(float dtime, bool send_recommended)
{
ScopeProfiler sp2(g_profiler, "FireflySAO::step avg", SPT_AVG);
assert(m_env);
if(m_is_active == false)
{
if(m_inactive_interval.step(dtime, 0.5)==false)
return;
}
/*
The AI
*/
// Apply (less) gravity
m_speed_f.Y -= dtime*3*BS;
/*
Move around if some player is close
*/
bool player_is_close = false;
// Check connected players
core::list<Player*> players = m_env->getPlayers(true);
core::list<Player*>::Iterator i;
for(i = players.begin();
i != players.end(); i++)
{
Player *player = *i;
v3f playerpos = player->getPosition();
if(m_base_position.getDistanceFrom(playerpos) < BS*10.0)
{
player_is_close = true;
break;
}
}
m_is_active = player_is_close;
if(player_is_close == false)
{
m_speed_f.X = 0;
m_speed_f.Z = 0;
}
else
{
// Move around
v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
f32 speed = BS/2;
m_speed_f.X = speed * dir.X;
m_speed_f.Z = speed * dir.Z;
if(m_touching_ground && (m_oldpos - m_base_position).getLength()
< dtime*speed/2)
{
m_counter1 -= dtime;
if(m_counter1 < 0.0)
{
m_counter1 += 1.0;
m_speed_f.Y = 5.0*BS;
}
}
{
m_counter2 -= dtime;
if(m_counter2 < 0.0)
{
m_counter2 += (float)(myrand()%100)/100*3.0;
m_yaw += ((float)(myrand()%200)-100)/100*180;
m_yaw = wrapDegrees(m_yaw);
}
}
}
m_oldpos = m_base_position;
/*
Move it, with collision detection
*/
core::aabbox3d<f32> box(-BS/3.,-BS*2/3.0,-BS/3., BS/3.,BS*4./3.,BS/3.);
collisionMoveResult moveresult;
// Maximum movement without glitches
f32 pos_max_d = BS*0.25;
// Limit speed
if(m_speed_f.getLength()*dtime > pos_max_d)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
IGameDef *gamedef = m_env->getGameDef();
moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
pos_max_d, box, dtime, pos_f, m_speed_f);
m_touching_ground = moveresult.touching_ground;
setBasePosition(pos_f);
if(send_recommended == false)
return;
if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
{
m_last_sent_position = pos_f;
std::ostringstream os(std::ios::binary);
// command (0 = update position)
writeU8(os, AO_Message_type::SetPosition);
// pos
writeV3F1000(os, m_base_position);
// yaw
writeF1000(os, m_yaw);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
std::string FireflySAO::getClientInitializationData()
{
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
// pos
writeV3F1000(os, m_base_position);
return os.str();
}
std::string FireflySAO::getStaticData()
{
//infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
return os.str();
}
// Prototype
FireflySAO proto_FireflySAO(NULL, v3f(0,0,0));

49
src/content_sao_firefly.h Normal file
View File

@@ -0,0 +1,49 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef CONTENT_SOA_FIREFLY_H_
#define CONTENT_SOA_FIREFLY_H_
#include "content_sao.h"
class FireflySAO : public ServerActiveObject
{
public:
FireflySAO(ServerEnvironment *env, v3f pos);
u8 getType() const
{return ACTIVEOBJECT_TYPE_FIREFLY;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
private:
bool m_is_active;
IntervalLimiter m_inactive_interval;
v3f m_speed_f;
v3f m_oldpos;
v3f m_last_sent_position;
float m_yaw;
float m_counter1;
float m_counter2;
float m_age;
bool m_touching_ground;
};
#endif /* CONTENT_SOA_FIREFLY_H_ */

167
src/content_sao_item.cpp Normal file
View File

@@ -0,0 +1,167 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content_sao_item.h"
/*
ItemSAO
*/
ItemSAO::ItemSAO(ServerEnvironment *env, v3f pos,
const std::string inventorystring):
ServerActiveObject(env, pos),
m_inventorystring(inventorystring),
m_speed_f(0,0,0),
m_last_sent_position(0,0,0)
{
ServerActiveObject::registerType(getType(), create);
}
ServerActiveObject* ItemSAO::create(ServerEnvironment *env, v3f pos,
const std::string &data)
{
std::istringstream is(data, std::ios::binary);
char buf[1];
// read version
is.read(buf, 1);
u8 version = buf[0];
// check if version is supported
if(version != 0)
return NULL;
std::string inventorystring = deSerializeString(is);
infostream<<"ItemSAO::create(): Creating item \""
<<inventorystring<<"\""<<std::endl;
return new ItemSAO(env, pos, inventorystring);
}
void ItemSAO::step(float dtime, bool send_recommended)
{
ScopeProfiler sp2(g_profiler, "ItemSAO::step avg", SPT_AVG);
assert(m_env);
const float interval = 0.2;
if(m_move_interval.step(dtime, interval)==false)
return;
dtime = interval;
core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
collisionMoveResult moveresult;
// Apply gravity
m_speed_f += v3f(0, -dtime*9.81*BS, 0);
// Maximum movement without glitches
f32 pos_max_d = BS*0.25;
// Limit speed
if(m_speed_f.getLength()*dtime > pos_max_d)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
IGameDef *gamedef = m_env->getGameDef();
moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
pos_max_d, box, dtime, pos_f, m_speed_f);
if(send_recommended == false)
return;
if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
{
setBasePosition(pos_f);
m_last_sent_position = pos_f;
std::ostringstream os(std::ios::binary);
char buf[6];
// command (0 = update position)
buf[0] = AO_Message_type::SetPosition;
os.write(buf, 1);
// pos
writeS32((u8*)buf, m_base_position.X*1000);
os.write(buf, 4);
writeS32((u8*)buf, m_base_position.Y*1000);
os.write(buf, 4);
writeS32((u8*)buf, m_base_position.Z*1000);
os.write(buf, 4);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
std::string ItemSAO::getClientInitializationData()
{
std::ostringstream os(std::ios::binary);
char buf[6];
// version
buf[0] = 0;
os.write(buf, 1);
// pos
writeS32((u8*)buf, m_base_position.X*1000);
os.write(buf, 4);
writeS32((u8*)buf, m_base_position.Y*1000);
os.write(buf, 4);
writeS32((u8*)buf, m_base_position.Z*1000);
os.write(buf, 4);
// inventorystring
os<<serializeString(m_inventorystring);
return os.str();
}
std::string ItemSAO::getStaticData()
{
infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
char buf[1];
// version
buf[0] = 0;
os.write(buf, 1);
// inventorystring
os<<serializeString(m_inventorystring);
return os.str();
}
InventoryItem * ItemSAO::createInventoryItem()
{
try{
std::istringstream is(m_inventorystring, std::ios_base::binary);
IGameDef *gamedef = m_env->getGameDef();
InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
<<m_inventorystring<<"\" -> item="<<item
<<std::endl;
return item;
}
catch(SerializationError &e)
{
infostream<<__FUNCTION_NAME<<": serialization error: "
<<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
return NULL;
}
}
void ItemSAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
InventoryItem *item = createInventoryItem();
bool fits = puncher->addToInventory(item);
if(fits)
m_removed = true;
else
delete item;
}
// Prototype
ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), "");

47
src/content_sao_item.h Normal file
View File

@@ -0,0 +1,47 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef CONTENT_SAO_ITEM_H_
#define CONTENT_SAO_ITEM_H_
#include "content_sao.h"
class ItemSAO : public ServerActiveObject
{
public:
ItemSAO(ServerEnvironment *env, v3f pos,
const std::string inventorystring);
u8 getType() const
{return ACTIVEOBJECT_TYPE_ITEM;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
InventoryItem* createInventoryItem();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
float getMinimumSavedMovement(){ return 0.1*BS; }
private:
std::string m_inventorystring;
v3f m_speed_f;
v3f m_last_sent_position;
IntervalLimiter m_move_interval;
};
#endif /* CONTENT_SAO_ITEM_H_ */

344
src/content_sao_lua.cpp Normal file
View File

@@ -0,0 +1,344 @@
/*
Minetest-c55
Copyright (C) 2010-2012 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 <iostream>
#include "content_sao_lua.h"
/*
LuaEntitySAO
*/
LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
const std::string &name, const std::string &state):
ServerActiveObject(env, pos),
m_init_name(name),
m_init_state(state),
m_registered(false),
m_prop(new LuaEntityProperties),
m_velocity(0,0,0),
m_acceleration(0,0,0),
m_yaw(0),
m_last_sent_yaw(0),
m_last_sent_position(0,0,0),
m_last_sent_velocity(0,0,0),
m_last_sent_position_timer(0),
m_last_sent_move_precision(0)
{
// Only register type if no environment supplied
if(env == NULL){
ServerActiveObject::registerType(getType(), create);
return;
}
}
LuaEntitySAO::~LuaEntitySAO()
{
if(m_registered){
lua_State *L = m_env->getLua();
scriptapi_luaentity_rm(L, m_id);
}
delete m_prop;
}
void LuaEntitySAO::addedToEnvironment()
{
ServerActiveObject::addedToEnvironment();
// Create entity from name and state
lua_State *L = m_env->getLua();
m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str(),
m_init_state.c_str());
if(m_registered){
// Get properties
scriptapi_luaentity_get_properties(L, m_id, m_prop);
}
}
ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
const std::string &data)
{
std::istringstream is(data, std::ios::binary);
// read version
u8 version = readU8(is);
// check if version is supported
if(version != 0)
return NULL;
// read name
std::string name = deSerializeString(is);
// read state
std::string state = deSerializeLongString(is);
// create object
infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\""
<<state<<"\")"<<std::endl;
return new LuaEntitySAO(env, pos, name, state);
}
void LuaEntitySAO::step(float dtime, bool send_recommended)
{
//errorstream << this << " step: old_vel=(" << m_velocity.X << "," << m_velocity.Y << "," << m_velocity.Z << ")" << std::endl;
//errorstream << this << " step: old_pos=(" << m_base_position.X << "," << m_base_position.Y << "," << m_base_position.Z << ")" << std::endl;
m_last_sent_position_timer += dtime;
if(m_prop->physical){
core::aabbox3d<f32> box = m_prop->collisionbox;
box.MinEdge *= BS;
box.MaxEdge *= BS;
collisionMoveResult moveresult;
f32 pos_max_d = BS*0.25; // Distance per iteration
v3f p_pos = getBasePosition();
v3f p_velocity = m_velocity;
IGameDef *gamedef = m_env->getGameDef();
moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
pos_max_d, box, dtime, p_pos, p_velocity);
// Apply results
setBasePosition(p_pos);
m_velocity = p_velocity;
//if (moveresult.collides) errorstream << "collision" << std::endl;
//if (moveresult.touching_ground) errorstream << "ground" << std::endl;
m_velocity += dtime * m_acceleration;
} else {
m_base_position += dtime * m_velocity + 0.5 * dtime
* dtime * m_acceleration;
m_velocity += dtime * m_acceleration;
}
//errorstream << this << " step: new_vel=(" << m_velocity.X << "," << m_velocity.Y << "," << m_velocity.Z << ")" << std::endl;
//errorstream << this << " step: new_pos=(" << m_base_position.X << "," << m_base_position.Y << "," << m_base_position.Z << ")" << std::endl;
if(m_registered){
lua_State *L = m_env->getLua();
scriptapi_luaentity_step(L, m_id, dtime);
}
if(send_recommended == false)
return;
// TODO: force send when acceleration changes enough?
float minchange = 0.2*BS;
if(m_last_sent_position_timer > 1.0){
minchange = 0.01*BS;
} else if(m_last_sent_position_timer > 0.2){
minchange = 0.05*BS;
}
float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
move_d += m_last_sent_move_precision;
float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
if(move_d > minchange || vel_d > minchange ||
fabs(m_yaw - m_last_sent_yaw) > 1.0 ||
m_last_sent_position_timer > 10.0){
sendPosition(true, false);
}
}
std::string LuaEntitySAO::getClientInitializationData()
{
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
// pos
writeV3F1000(os, m_base_position);
// yaw
writeF1000(os, m_yaw);
// properties
std::ostringstream prop_os(std::ios::binary);
m_prop->serialize(prop_os);
os<<serializeLongString(prop_os.str());
// return result
return os.str();
}
std::string LuaEntitySAO::getStaticData()
{
infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
// name
os<<serializeString(m_init_name);
// state
if(m_registered){
lua_State *L = m_env->getLua();
std::string state = scriptapi_luaentity_get_staticdata(L, m_id);
os<<serializeLongString(state);
} else {
os<<serializeLongString(m_init_state);
}
return os.str();
}
void LuaEntitySAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
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);
}
void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
{
if(!m_registered)
return;
lua_State *L = m_env->getLua();
scriptapi_luaentity_rightclick(L, m_id, clicker);
}
void LuaEntitySAO::setPos(v3f pos)
{
m_base_position = pos;
sendPosition(false, true);
}
void LuaEntitySAO::moveTo(v3f pos, bool continuous)
{
m_base_position = pos;
if(!continuous)
sendPosition(true, true);
}
float LuaEntitySAO::getMinimumSavedMovement()
{
return 0.1 * BS;
}
void LuaEntitySAO::setVelocity(v3f velocity)
{
//errorstream << this << " Set velocity: (" << velocity.X << "," << velocity.Y << "," <<velocity.Z << ")" << std::endl;
m_velocity = velocity;
}
v3f LuaEntitySAO::getVelocity()
{
return m_velocity;
}
void LuaEntitySAO::setAcceleration(v3f acceleration)
{
m_acceleration = acceleration;
}
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);
// command (1 = set texture modification)
writeU8(os, AO_Message_type::SetTextureMod);
// parameters
os<<serializeString(mod);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
bool select_horiz_by_yawpitch)
{
std::ostringstream os(std::ios::binary);
// command (2 = set sprite)
writeU8(os, AO_Message_type::SetSprite);
// parameters
writeV2S16(os, p);
writeU16(os, num_frames);
writeF1000(os, framelength);
writeU8(os, select_horiz_by_yawpitch);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
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(
m_last_sent_position);
m_last_sent_position_timer = 0;
m_last_sent_yaw = m_yaw;
m_last_sent_position = m_base_position;
m_last_sent_velocity = m_velocity;
//m_last_sent_acceleration = m_acceleration;
float update_interval = m_env->getSendRecommendedInterval();
std::ostringstream os(std::ios::binary);
// command (0 = update position)
writeU8(os, AO_Message_type::SetPosition);
// do_interpolate
writeU8(os, do_interpolate);
// pos
writeV3F1000(os, m_base_position);
// velocity
writeV3F1000(os, m_velocity);
// acceleration
writeV3F1000(os, m_acceleration);
// yaw
writeF1000(os, m_yaw);
// is_end_position (for interpolation)
writeU8(os, is_movement_end);
// update_interval (for interpolation)
writeF1000(os, update_interval);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
bool LuaEntitySAO::sendLinkMsg(ServerActiveObject* parent,v3f offset) {
std::ostringstream os(std::ios::binary);
writeU8(os, AO_Message_type::Link);
// parameters
writeU16(os, parent->getId());
writeV3F1000(os, offset);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
return true;
}
bool LuaEntitySAO::sendUnlinkMsg() {
std::ostringstream os(std::ios::binary);
writeU8(os, AO_Message_type::UnLink);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
return true;
}
// Prototype
LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", "");

80
src/content_sao_lua.h Normal file
View File

@@ -0,0 +1,80 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef CONTENT_SAO_LUA_H_
#define CONTENT_SAO_LUA_H_
#include "content_sao.h"
#include "serverlinkableobject.h"
#include "scriptapi.h"
#include "luaentity_common.h"
class LuaEntitySAO : public ServerActiveObject, public ServerLinkableObject
{
public:
LuaEntitySAO(ServerEnvironment *env, v3f pos,
const std::string &name, const std::string &state);
~LuaEntitySAO();
u8 getType() const
{return ACTIVEOBJECT_TYPE_LUAENTITY;}
virtual void addedToEnvironment();
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
void rightClick(ServerActiveObject *clicker);
void setPos(v3f pos);
void moveTo(v3f pos, bool continuous);
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();
bool sendLinkMsg(ServerActiveObject* parent,v3f offset);
bool sendUnlinkMsg();
private:
void sendPosition(bool do_interpolate, bool is_movement_end);
std::string m_init_name;
std::string m_init_state;
bool m_registered;
struct LuaEntityProperties *m_prop;
v3f m_velocity;
v3f m_acceleration;
float m_yaw;
float m_last_sent_yaw;
v3f m_last_sent_position;
v3f m_last_sent_velocity;
float m_last_sent_position_timer;
float m_last_sent_move_precision;
};
#endif /* CONTENT_SAO_LUA_H_ */

522
src/content_sao_mobv2.cpp Normal file
View File

@@ -0,0 +1,522 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content_sao_mobv2.h"
/*
MobV2SAO
*/
MobV2SAO::MobV2SAO(ServerEnvironment *env, v3f pos,
Settings *init_properties):
ServerActiveObject(env, pos),
m_move_type("ground_nodes"),
m_speed(0,0,0),
m_last_sent_position(0,0,0),
m_oldpos(0,0,0),
m_yaw(0),
m_counter1(0),
m_counter2(0),
m_age(0),
m_touching_ground(false),
m_hp(10),
m_walk_around(false),
m_walk_around_timer(0),
m_next_pos_exists(false),
m_shoot_reload_timer(0),
m_shooting(false),
m_shooting_timer(0),
m_falling(false),
m_disturb_timer(100000),
m_random_disturb_timer(0),
m_shoot_y(0)
{
ServerActiveObject::registerType(getType(), create);
m_properties = new Settings();
if(init_properties)
m_properties->update(*init_properties);
m_properties->setV3F("pos", pos);
setPropertyDefaults();
readProperties();
}
MobV2SAO::~MobV2SAO()
{
delete m_properties;
}
ServerActiveObject* MobV2SAO::create(ServerEnvironment *env, v3f pos,
const std::string &data)
{
std::istringstream is(data, std::ios::binary);
Settings properties;
properties.parseConfigLines(is, "MobArgsEnd");
MobV2SAO *o = new MobV2SAO(env, pos, &properties);
return o;
}
std::string MobV2SAO::getStaticData()
{
updateProperties();
std::ostringstream os(std::ios::binary);
m_properties->writeLines(os);
return os.str();
}
std::string MobV2SAO::getClientInitializationData()
{
//infostream<<__FUNCTION_NAME<<std::endl;
updateProperties();
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
Settings client_properties;
/*client_properties.set("version", "0");
client_properties.updateValue(*m_properties, "pos");
client_properties.updateValue(*m_properties, "yaw");
client_properties.updateValue(*m_properties, "hp");*/
// Just send everything for simplicity
client_properties.update(*m_properties);
std::ostringstream os2(std::ios::binary);
client_properties.writeLines(os2);
compressZlib(os2.str(), os);
return os.str();
}
void MobV2SAO::step(float dtime, bool send_recommended)
{
ScopeProfiler sp2(g_profiler, "MobV2SAO::step avg", SPT_AVG);
assert(m_env);
Map *map = &m_env->getMap();
m_age += dtime;
if(m_die_age >= 0.0 && m_age >= m_die_age){
m_removed = true;
return;
}
m_random_disturb_timer += dtime;
if(m_random_disturb_timer >= 5.0)
{
m_random_disturb_timer = 0;
// Check connected players
core::list<Player*> players = m_env->getPlayers(true);
core::list<Player*>::Iterator i;
for(i = players.begin();
i != players.end(); i++)
{
Player *player = *i;
v3f playerpos = player->getPosition();
f32 dist = m_base_position.getDistanceFrom(playerpos);
if(dist < BS*16)
{
if(myrand_range(0,3) == 0){
actionstream<<"Mob id="<<m_id<<" at "
<<PP(m_base_position/BS)
<<" got randomly disturbed by "
<<player->getName()<<std::endl;
m_disturbing_player = player->getName();
m_disturb_timer = 0;
break;
}
}
}
}
Player *disturbing_player =
m_env->getPlayer(m_disturbing_player.c_str());
v3f disturbing_player_off = v3f(0,1,0);
v3f disturbing_player_norm = v3f(0,1,0);
float disturbing_player_distance = 1000000;
float disturbing_player_dir = 0;
if(disturbing_player){
disturbing_player_off =
disturbing_player->getPosition() - m_base_position;
disturbing_player_distance = disturbing_player_off.getLength();
disturbing_player_norm = disturbing_player_off;
disturbing_player_norm.normalize();
disturbing_player_dir = 180./PI*atan2(disturbing_player_norm.Z,
disturbing_player_norm.X);
}
m_disturb_timer += dtime;
if(!m_falling)
{
m_shooting_timer -= dtime;
if(m_shooting_timer <= 0.0 && m_shooting){
m_shooting = false;
std::string shoot_type = m_properties->get("shoot_type");
v3f shoot_pos(0,0,0);
shoot_pos.Y += m_properties->getFloat("shoot_y") * BS;
if(shoot_type == "fireball"){
v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
dir.Y = m_shoot_y;
dir.normalize();
v3f speed = dir * BS * 10.0;
v3f pos = m_base_position + shoot_pos;
infostream<<__FUNCTION_NAME<<": Mob id="<<m_id
<<" shooting fireball from "<<PP(pos)
<<" at speed "<<PP(speed)<<std::endl;
Settings properties;
properties.set("looks", "fireball");
properties.setV3F("speed", speed);
properties.setFloat("die_age", 5.0);
properties.set("move_type", "constant_speed");
properties.setFloat("hp", 1000);
properties.set("lock_full_brightness", "true");
properties.set("player_hit_damage", "9");
properties.set("player_hit_distance", "2");
properties.set("player_hit_interval", "1");
ServerActiveObject *obj = new MobV2SAO(m_env,
pos, &properties);
//m_env->addActiveObjectAsStatic(obj);
m_env->addActiveObject(obj);
} else {
infostream<<__FUNCTION_NAME<<": Mob id="<<m_id
<<": Unknown shoot_type="<<shoot_type
<<std::endl;
}
}
m_shoot_reload_timer += dtime;
float reload_time = 15.0;
if(m_disturb_timer <= 15.0)
reload_time = 3.0;
bool shoot_without_player = false;
if(m_properties->getBool("mindless_rage"))
shoot_without_player = true;
if(!m_shooting && m_shoot_reload_timer >= reload_time &&
!m_next_pos_exists &&
(m_disturb_timer <= 60.0 || shoot_without_player))
{
m_shoot_y = 0;
if(m_disturb_timer < 60.0 && disturbing_player &&
disturbing_player_distance < 16*BS &&
fabs(disturbing_player_norm.Y) < 0.8){
m_yaw = disturbing_player_dir;
sendPosition();
m_shoot_y += disturbing_player_norm.Y;
} else {
m_shoot_y = 0.01 * myrand_range(-30,10);
}
m_shoot_reload_timer = 0.0;
m_shooting = true;
m_shooting_timer = 1.5;
{
std::ostringstream os(std::ios::binary);
// command (2 = shooting)
writeU8(os, AO_Message_type::Shoot);
// time
writeF1000(os, m_shooting_timer + 0.1);
// bright?
writeU8(os, true);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
}
if(m_move_type == "ground_nodes")
{
if(!m_shooting){
m_walk_around_timer -= dtime;
if(m_walk_around_timer <= 0.0){
m_walk_around = !m_walk_around;
if(m_walk_around)
m_walk_around_timer = 0.1*myrand_range(10,50);
else
m_walk_around_timer = 0.1*myrand_range(30,70);
}
}
/* Move */
if(m_next_pos_exists){
v3f pos_f = m_base_position;
v3f next_pos_f = intToFloat(m_next_pos_i, BS);
v3f v = next_pos_f - pos_f;
m_yaw = atan2(v.Z, v.X) / PI * 180;
v3f diff = next_pos_f - pos_f;
v3f dir = diff;
dir.normalize();
float speed = BS * 0.5;
if(m_falling)
speed = BS * 3.0;
dir *= dtime * speed;
bool arrived = false;
if(dir.getLength() > diff.getLength()){
dir = diff;
arrived = true;
}
pos_f += dir;
m_base_position = pos_f;
if((pos_f - next_pos_f).getLength() < 0.1 || arrived){
m_next_pos_exists = false;
}
}
v3s16 pos_i = floatToInt(m_base_position, BS);
v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
v3s16 pos_size_off(0,0,0);
if(m_size.X >= 2.5){
pos_size_off.X = -1;
pos_size_off.Y = -1;
}
if(!m_next_pos_exists){
/* Check whether to drop down */
if(checkFreePosition(map,
pos_i + pos_size_off + v3s16(0,-1,0), size_blocks)){
m_next_pos_i = pos_i + v3s16(0,-1,0);
m_next_pos_exists = true;
m_falling = true;
} else {
m_falling = false;
}
}
if(m_walk_around)
{
if(!m_next_pos_exists){
/* Find some position where to go next */
v3s16 dps[3*3*3];
int num_dps = 0;
for(int dx=-1; dx<=1; dx++)
for(int dy=-1; dy<=1; dy++)
for(int dz=-1; dz<=1; dz++){
if(dx == 0 && dy == 0)
continue;
if(dx != 0 && dz != 0 && dy != 0)
continue;
dps[num_dps++] = v3s16(dx,dy,dz);
}
u32 order[3*3*3];
get_random_u32_array(order, num_dps);
for(int i=0; i<num_dps; i++){
v3s16 p = dps[order[i]] + pos_i;
bool is_free = checkFreeAndWalkablePosition(map,
p + pos_size_off, size_blocks);
if(!is_free)
continue;
m_next_pos_i = p;
m_next_pos_exists = true;
break;
}
}
}
}
else if(m_move_type == "constant_speed")
{
m_base_position += m_speed * dtime;
v3s16 pos_i = floatToInt(m_base_position, BS);
v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
v3s16 pos_size_off(0,0,0);
if(m_size.X >= 2.5){
pos_size_off.X = -1;
pos_size_off.Y = -1;
}
bool free = checkFreePosition(map, pos_i + pos_size_off, size_blocks);
if(!free){
explodeSquare(map, pos_i, v3s16(3,3,3));
m_removed = true;
return;
}
}
else
{
errorstream<<"MobV2SAO::step(): id="<<m_id<<" unknown move_type=\""
<<m_move_type<<"\""<<std::endl;
}
if(send_recommended == false)
return;
if(m_base_position.getDistanceFrom(m_last_sent_position) > 0.05*BS)
{
sendPosition();
}
}
void MobV2SAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
if(!puncher)
return;
v3f dir = (getBasePosition() - puncher->getBasePosition()).normalize();
// A quick hack; SAO description is player name for player
std::string playername = puncher->getDescription();
Map *map = &m_env->getMap();
actionstream<<playername<<" punches mob id="<<m_id
<<" at "<<PP(m_base_position/BS)<<std::endl;
m_disturb_timer = 0;
m_disturbing_player = playername;
m_next_pos_exists = false; // Cancel moving immediately
m_yaw = wrapDegrees_180(180./PI*atan2(dir.Z, dir.X) + 180.);
v3f new_base_position = m_base_position + dir * BS;
{
v3s16 pos_i = floatToInt(new_base_position, BS);
v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
v3s16 pos_size_off(0,0,0);
if(m_size.X >= 2.5){
pos_size_off.X = -1;
pos_size_off.Y = -1;
}
bool free = checkFreePosition(map, pos_i + pos_size_off, size_blocks);
if(free)
m_base_position = new_base_position;
}
sendPosition();
// "Material" properties of the MobV2
MaterialProperties mp;
mp.diggability = DIGGABLE_NORMAL;
mp.crackiness = -1.0;
mp.cuttability = 1.0;
ToolDiggingProperties tp;
puncher->getWieldDiggingProperties(&tp);
HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch);
doDamage(hitprop.hp);
puncher->damageWieldedItem(hitprop.wear);
}
bool MobV2SAO::isPeaceful()
{
return m_properties->getBool("is_peaceful");
}
void MobV2SAO::sendPosition()
{
m_last_sent_position = m_base_position;
std::ostringstream os(std::ios::binary);
// command (0 = update position)
writeU8(os, AO_Message_type::SetPosition);
// pos
writeV3F1000(os, m_base_position);
// yaw
writeF1000(os, m_yaw);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
void MobV2SAO::setPropertyDefaults()
{
m_properties->setDefault("is_peaceful", "false");
m_properties->setDefault("move_type", "ground_nodes");
m_properties->setDefault("speed", "(0,0,0)");
m_properties->setDefault("age", "0");
m_properties->setDefault("yaw", "0");
m_properties->setDefault("pos", "(0,0,0)");
m_properties->setDefault("hp", "0");
m_properties->setDefault("die_age", "-1");
m_properties->setDefault("size", "(1,2)");
m_properties->setDefault("shoot_type", "fireball");
m_properties->setDefault("shoot_y", "0");
m_properties->setDefault("mindless_rage", "false");
}
void MobV2SAO::readProperties()
{
m_move_type = m_properties->get("move_type");
m_speed = m_properties->getV3F("speed");
m_age = m_properties->getFloat("age");
m_yaw = m_properties->getFloat("yaw");
m_base_position = m_properties->getV3F("pos");
m_hp = m_properties->getS32("hp");
m_die_age = m_properties->getFloat("die_age");
m_size = m_properties->getV2F("size");
}
void MobV2SAO::updateProperties()
{
m_properties->set("move_type", m_move_type);
m_properties->setV3F("speed", m_speed);
m_properties->setFloat("age", m_age);
m_properties->setFloat("yaw", m_yaw);
m_properties->setV3F("pos", m_base_position);
m_properties->setS32("hp", m_hp);
m_properties->setFloat("die_age", m_die_age);
m_properties->setV2F("size", m_size);
m_properties->setS32("version", 0);
}
void MobV2SAO::doDamage(u16 d)
{
infostream<<"MobV2 hp="<<m_hp<<" damage="<<d<<std::endl;
if(d < m_hp)
{
m_hp -= d;
}
else
{
actionstream<<"A "<<(isPeaceful()?"peaceful":"non-peaceful")
<<" mob id="<<m_id<<" dies at "<<PP(m_base_position)<<std::endl;
// Die
m_hp = 0;
m_removed = true;
}
{
std::ostringstream os(std::ios::binary);
// command (1 = damage)
writeU8(os, AO_Message_type::TakeDamage);
// amount
writeU16(os, d);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
// Prototype
MobV2SAO proto_MobV2SAO(NULL, v3f(0,0,0), NULL);

76
src/content_sao_mobv2.h Normal file
View File

@@ -0,0 +1,76 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef CONTENT_SAO_MOBV2_H_
#define CONTENT_SAO_MOBV2_H_
#include "content_sao.h"
class MobV2SAO : public ServerActiveObject
{
public:
MobV2SAO(ServerEnvironment *env, v3f pos,
Settings *init_properties);
virtual ~MobV2SAO();
u8 getType() const
{return ACTIVEOBJECT_TYPE_MOBV2;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
std::string getStaticData();
std::string getClientInitializationData();
void step(float dtime, bool send_recommended);
void punch(ServerActiveObject *puncher, float time_from_last_punch);
bool isPeaceful();
private:
void sendPosition();
void setPropertyDefaults();
void readProperties();
void updateProperties();
void doDamage(u16 d);
std::string m_move_type;
v3f m_speed;
v3f m_last_sent_position;
v3f m_oldpos;
float m_yaw;
float m_counter1;
float m_counter2;
float m_age;
bool m_touching_ground;
int m_hp;
bool m_walk_around;
float m_walk_around_timer;
bool m_next_pos_exists;
v3s16 m_next_pos_i;
float m_shoot_reload_timer;
bool m_shooting;
float m_shooting_timer;
float m_die_age;
v2f m_size;
bool m_falling;
float m_disturb_timer;
std::string m_disturbing_player;
float m_random_disturb_timer;
float m_shoot_y;
Settings *m_properties;
};
#endif /* CONTENT_SAO_MOBV2_H_ */

314
src/content_sao_oerkki1.cpp Normal file
View File

@@ -0,0 +1,314 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content_sao_oerkki1.h"
/*
Oerkki1SAO
*/
Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, v3f pos):
ServerActiveObject(env, pos),
m_is_active(false),
m_speed_f(0,0,0)
{
ServerActiveObject::registerType(getType(), create);
m_oldpos = v3f(0,0,0);
m_last_sent_position = v3f(0,0,0);
m_yaw = 0;
m_counter1 = 0;
m_counter2 = 0;
m_age = 0;
m_touching_ground = false;
m_hp = 20;
m_after_jump_timer = 0;
}
ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, v3f pos,
const std::string &data)
{
std::istringstream is(data, std::ios::binary);
// read version
u8 version = readU8(is);
// read hp
u8 hp = readU8(is);
// check if version is supported
if(version != 0)
return NULL;
Oerkki1SAO *o = new Oerkki1SAO(env, pos);
o->m_hp = hp;
return o;
}
void Oerkki1SAO::step(float dtime, bool send_recommended)
{
ScopeProfiler sp2(g_profiler, "Oerkki1SAO::step avg", SPT_AVG);
assert(m_env);
if(m_is_active == false)
{
if(m_inactive_interval.step(dtime, 0.5)==false)
return;
}
/*
The AI
*/
m_age += dtime;
if(m_age > 120)
{
// Die
m_removed = true;
return;
}
m_after_jump_timer -= dtime;
v3f old_speed = m_speed_f;
// Apply gravity
m_speed_f.Y -= dtime*9.81*BS;
/*
Move around if some player is close
*/
bool player_is_close = false;
bool player_is_too_close = false;
v3f near_player_pos;
// Check connected players
core::list<Player*> players = m_env->getPlayers(true);
core::list<Player*>::Iterator i;
for(i = players.begin();
i != players.end(); i++)
{
Player *player = *i;
v3f playerpos = player->getPosition();
f32 dist = m_base_position.getDistanceFrom(playerpos);
if(dist < BS*0.6)
{
m_removed = true;
return;
player_is_too_close = true;
near_player_pos = playerpos;
}
else if(dist < BS*15.0 && !player_is_too_close)
{
player_is_close = true;
near_player_pos = playerpos;
}
}
m_is_active = player_is_close;
v3f target_speed = m_speed_f;
if(!player_is_close)
{
target_speed = v3f(0,0,0);
}
else
{
// Move around
v3f ndir = near_player_pos - m_base_position;
ndir.Y = 0;
ndir.normalize();
f32 nyaw = 180./PI*atan2(ndir.Z,ndir.X);
if(nyaw < m_yaw - 180)
nyaw += 360;
else if(nyaw > m_yaw + 180)
nyaw -= 360;
m_yaw = 0.95*m_yaw + 0.05*nyaw;
m_yaw = wrapDegrees(m_yaw);
f32 speed = 2*BS;
if((m_touching_ground || m_after_jump_timer > 0.0)
&& !player_is_too_close)
{
v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
target_speed.X = speed * dir.X;
target_speed.Z = speed * dir.Z;
}
if(m_touching_ground && (m_oldpos - m_base_position).getLength()
< dtime*speed/2)
{
m_counter1 -= dtime;
if(m_counter1 < 0.0)
{
m_counter1 += 0.2;
// Jump
target_speed.Y = 5.0*BS;
m_after_jump_timer = 1.0;
}
}
{
m_counter2 -= dtime;
if(m_counter2 < 0.0)
{
m_counter2 += (float)(myrand()%100)/100*3.0;
//m_yaw += ((float)(myrand()%200)-100)/100*180;
m_yaw += ((float)(myrand()%200)-100)/100*90;
m_yaw = wrapDegrees(m_yaw);
}
}
}
if((m_speed_f - target_speed).getLength() > BS*4 || player_is_too_close)
accelerate_xz(m_speed_f, target_speed, dtime*BS*8);
else
accelerate_xz(m_speed_f, target_speed, dtime*BS*4);
m_oldpos = m_base_position;
/*
Move it, with collision detection
*/
core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*5./3.,BS/3.);
collisionMoveResult moveresult;
// Maximum movement without glitches
f32 pos_max_d = BS*0.25;
/*// Limit speed
if(m_speed_f.getLength()*dtime > pos_max_d)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);*/
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
IGameDef *gamedef = m_env->getGameDef();
moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
pos_max_d, box, dtime, pos_f, m_speed_f);
m_touching_ground = moveresult.touching_ground;
// Do collision damage
float tolerance = BS*30;
float factor = BS*0.5;
v3f speed_diff = old_speed - m_speed_f;
// Increase effect in X and Z
speed_diff.X *= 2;
speed_diff.Z *= 2;
float vel = speed_diff.getLength();
if(vel > tolerance)
{
f32 damage_f = (vel - tolerance)/BS*factor;
u16 damage = (u16)(damage_f+0.5);
doDamage(damage);
}
setBasePosition(pos_f);
if(send_recommended == false && m_speed_f.getLength() < 3.0*BS)
return;
if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
{
m_last_sent_position = pos_f;
std::ostringstream os(std::ios::binary);
// command (0 = update position)
writeU8(os, AO_Message_type::SetPosition);
// pos
writeV3F1000(os, m_base_position);
// yaw
writeF1000(os, m_yaw);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
std::string Oerkki1SAO::getClientInitializationData()
{
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
// pos
writeV3F1000(os, m_base_position);
return os.str();
}
std::string Oerkki1SAO::getStaticData()
{
//infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
// hp
writeU8(os, m_hp);
return os.str();
}
void Oerkki1SAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
if(!puncher)
return;
v3f dir = (getBasePosition() - puncher->getBasePosition()).normalize();
m_speed_f += dir*12*BS;
// "Material" properties of an oerkki
MaterialProperties mp;
mp.diggability = DIGGABLE_NORMAL;
mp.crackiness = -1.0;
mp.cuttability = 1.0;
ToolDiggingProperties tp;
puncher->getWieldDiggingProperties(&tp);
HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch);
doDamage(hitprop.hp);
puncher->damageWieldedItem(hitprop.wear);
}
void Oerkki1SAO::doDamage(u16 d)
{
infostream<<"oerkki damage: "<<d<<std::endl;
if(d < m_hp)
{
m_hp -= d;
}
else
{
// Die
m_hp = 0;
m_removed = true;
}
{
std::ostringstream os(std::ios::binary);
// command (1 = damage)
writeU8(os, AO_Message_type::TakeDamage);
// amount
writeU8(os, d);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
// Prototype
Oerkki1SAO proto_Oerkki1SAO(NULL, v3f(0,0,0));

55
src/content_sao_oerkki1.h Normal file
View File

@@ -0,0 +1,55 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef CONTENT_SAO_OERKKI1_H_
#define CONTENT_SAO_OERKKI1_H_
#include "content_sao.h"
class Oerkki1SAO : public ServerActiveObject
{
public:
Oerkki1SAO(ServerEnvironment *env, v3f pos);
u8 getType() const
{return ACTIVEOBJECT_TYPE_OERKKI1;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
bool isPeaceful(){return false;}
private:
void doDamage(u16 d);
bool m_is_active;
IntervalLimiter m_inactive_interval;
v3f m_speed_f;
v3f m_oldpos;
v3f m_last_sent_position;
float m_yaw;
float m_counter1;
float m_counter2;
float m_age;
bool m_touching_ground;
u8 m_hp;
float m_after_jump_timer;
};
#endif /* CONTENT_SAO_OERKKI1_H_ */

212
src/content_sao_rat.cpp Normal file
View File

@@ -0,0 +1,212 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content_sao_rat.h"
/*
RatSAO
*/
RatSAO::RatSAO(ServerEnvironment *env, v3f pos):
ServerActiveObject(env, pos),
m_is_active(false),
m_speed_f(0,0,0)
{
ServerActiveObject::registerType(getType(), create);
m_oldpos = v3f(0,0,0);
m_last_sent_position = v3f(0,0,0);
m_yaw = myrand_range(0,PI*2);
m_counter1 = 0;
m_counter2 = 0;
m_age = 0;
m_touching_ground = false;
}
ServerActiveObject* RatSAO::create(ServerEnvironment *env, v3f pos,
const std::string &data)
{
std::istringstream is(data, std::ios::binary);
char buf[1];
// read version
is.read(buf, 1);
u8 version = buf[0];
// check if version is supported
if(version != 0)
return NULL;
return new RatSAO(env, pos);
}
void RatSAO::step(float dtime, bool send_recommended)
{
ScopeProfiler sp2(g_profiler, "RatSAO::step avg", SPT_AVG);
assert(m_env);
if(m_is_active == false)
{
if(m_inactive_interval.step(dtime, 0.5)==false)
return;
}
/*
The AI
*/
/*m_age += dtime;
if(m_age > 60)
{
// Die
m_removed = true;
return;
}*/
// Apply gravity
m_speed_f.Y -= dtime*9.81*BS;
/*
Move around if some player is close
*/
bool player_is_close = false;
// Check connected players
core::list<Player*> players = m_env->getPlayers(true);
core::list<Player*>::Iterator i;
for(i = players.begin();
i != players.end(); i++)
{
Player *player = *i;
v3f playerpos = player->getPosition();
if(m_base_position.getDistanceFrom(playerpos) < BS*10.0)
{
player_is_close = true;
break;
}
}
m_is_active = player_is_close;
if(player_is_close == false)
{
m_speed_f.X = 0;
m_speed_f.Z = 0;
}
else
{
// Move around
v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
f32 speed = 2*BS;
m_speed_f.X = speed * dir.X;
m_speed_f.Z = speed * dir.Z;
if(m_touching_ground && (m_oldpos - m_base_position).getLength()
< dtime*speed/2)
{
m_counter1 -= dtime;
if(m_counter1 < 0.0)
{
m_counter1 += 1.0;
m_speed_f.Y = 5.0*BS;
}
}
{
m_counter2 -= dtime;
if(m_counter2 < 0.0)
{
m_counter2 += (float)(myrand()%100)/100*3.0;
m_yaw += ((float)(myrand()%200)-100)/100*180;
m_yaw = wrapDegrees(m_yaw);
}
}
}
m_oldpos = m_base_position;
/*
Move it, with collision detection
*/
core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
collisionMoveResult moveresult;
// Maximum movement without glitches
f32 pos_max_d = BS*0.25;
// Limit speed
if(m_speed_f.getLength()*dtime > pos_max_d)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
IGameDef *gamedef = m_env->getGameDef();
moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
pos_max_d, box, dtime, pos_f, m_speed_f);
m_touching_ground = moveresult.touching_ground;
setBasePosition(pos_f);
if(send_recommended == false)
return;
if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
{
m_last_sent_position = pos_f;
std::ostringstream os(std::ios::binary);
// command (0 = update position)
writeU8(os, 0);
// pos
writeV3F1000(os, m_base_position);
// yaw
writeF1000(os, m_yaw);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
std::string RatSAO::getClientInitializationData()
{
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
// pos
writeV3F1000(os, m_base_position);
return os.str();
}
std::string RatSAO::getStaticData()
{
//infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
return os.str();
}
void RatSAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
std::istringstream is("CraftItem rat 1", std::ios_base::binary);
IGameDef *gamedef = m_env->getGameDef();
InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
bool fits = puncher->addToInventory(item);
if(fits)
m_removed = true;
else
delete item;
}
// Prototype
RatSAO proto_RatSAO(NULL, v3f(0,0,0));

50
src/content_sao_rat.h Normal file
View File

@@ -0,0 +1,50 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef CONTENT_SAO_RAT_H_
#define CONTENT_SAO_RAT_H_
#include "content_sao.h"
class RatSAO : public ServerActiveObject
{
public:
RatSAO(ServerEnvironment *env, v3f pos);
u8 getType() const
{return ACTIVEOBJECT_TYPE_RAT;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
private:
bool m_is_active;
IntervalLimiter m_inactive_interval;
v3f m_speed_f;
v3f m_oldpos;
v3f m_last_sent_position;
float m_yaw;
float m_counter1;
float m_counter2;
float m_age;
bool m_touching_ground;
};
#endif /* CONTENT_SAO_RAT_H_ */

90
src/content_sao_test.cpp Normal file
View File

@@ -0,0 +1,90 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content_sao.h"
class TestSAO : public ServerActiveObject
{
public:
TestSAO(ServerEnvironment *env, v3f pos);
u8 getType() const
{return ACTIVEOBJECT_TYPE_TEST;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
private:
float m_timer1;
float m_age;
};
/*
TestSAO
*/
TestSAO::TestSAO(ServerEnvironment *env, v3f pos):
ServerActiveObject(env, pos),
m_timer1(0),
m_age(0)
{
ServerActiveObject::registerType(getType(), create);
}
ServerActiveObject* TestSAO::create(ServerEnvironment *env, v3f pos,
const std::string &data)
{
return new TestSAO(env, pos);
}
void TestSAO::step(float dtime, bool send_recommended)
{
m_age += dtime;
if(m_age > 10)
{
m_removed = true;
return;
}
m_base_position.Y += dtime * BS * 2;
if(m_base_position.Y > 8*BS)
m_base_position.Y = 2*BS;
if(send_recommended == false)
return;
m_timer1 -= dtime;
if(m_timer1 < 0.0)
{
m_timer1 += 0.125;
std::string data;
data += itos(AO_Message_type::SetPosition); // 0 = position
data += " ";
data += itos(m_base_position.X);
data += " ";
data += itos(m_base_position.Y);
data += " ";
data += itos(m_base_position.Z);
ActiveObjectMessage aom(getId(), false, data);
m_messages_out.push_back(aom);
}
}

View File

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

View File

@@ -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;
@@ -747,11 +765,43 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
abmhandler.apply(block);
}
core::list<MapNode> ServerEnvironment::getNodesInsideRadius(v3s16 pos, float radius)
{
core::list<MapNode> nodes;
for (int i = pos.X - radius; i < pos.X + radius; i ++)
for (int j = pos.Y - radius; j < pos.Y + radius; j ++)
for (int k = pos.Z - radius; k < pos.Z + radius; k ++) {
v3s16 current_pos = v3s16(i,j,k);
if (current_pos.getDistanceFrom(pos) < radius) {
MapNode n = m_map->getNodeNoEx(current_pos);
nodes.push_back(n);
}
}
return nodes;
}
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(): "
@@ -1840,6 +1890,7 @@ void ClientEnvironment::step(float dtime)
Get the speed the player is going
*/
bool is_climbing = lplayer->is_climbing;
bool linked = lplayer->m_linked;
f32 player_speed = lplayer->getSpeed().getLength();
@@ -1868,96 +1919,98 @@ void ClientEnvironment::step(float dtime)
/*
Stuff that has a maximum time increment
*/
//TODO at this position possibly a better solution is required!
if (!linked) {
u32 loopcount = 0;
do
{
loopcount++;
u32 loopcount = 0;
do
{
loopcount++;
f32 dtime_part;
if(dtime_downcount > dtime_max_increment)
{
dtime_part = dtime_max_increment;
dtime_downcount -= dtime_part;
}
else
{
dtime_part = dtime_downcount;
/*
Setting this to 0 (no -=dtime_part) disables an infinite loop
when dtime_part is so small that dtime_downcount -= dtime_part
does nothing
*/
dtime_downcount = 0;
}
/*
Handle local player
*/
{
v3f lplayerpos = lplayer->getPosition();
// Apply physics
if(free_move == false && is_climbing == false)
f32 dtime_part;
if(dtime_downcount > dtime_max_increment)
{
// Gravity
v3f speed = lplayer->getSpeed();
if(lplayer->swimming_up == false)
speed.Y -= 9.81 * BS * dtime_part * 2;
// Water resistance
if(lplayer->in_water_stable || lplayer->in_water)
{
f32 max_down = 2.0*BS;
if(speed.Y < -max_down) speed.Y = -max_down;
f32 max = 2.5*BS;
if(speed.getLength() > max)
{
speed = speed / speed.getLength() * max;
}
}
lplayer->setSpeed(speed);
dtime_part = dtime_max_increment;
dtime_downcount -= dtime_part;
}
else
{
dtime_part = dtime_downcount;
/*
Setting this to 0 (no -=dtime_part) disables an infinite loop
when dtime_part is so small that dtime_downcount -= dtime_part
does nothing
*/
dtime_downcount = 0;
}
/*
Move the lplayer.
This also does collision detection.
Handle local player
*/
lplayer->move(dtime_part, *m_map, position_max_increment,
&player_collisions);
}
}
while(dtime_downcount > 0.001);
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
for(core::list<CollisionInfo>::Iterator
i = player_collisions.begin();
i != player_collisions.end(); i++)
{
CollisionInfo &info = *i;
if(info.t == COLLISION_FALL)
{
//f32 tolerance = BS*10; // 2 without damage
f32 tolerance = BS*12; // 3 without damage
f32 factor = 1;
if(info.speed > tolerance)
{
f32 damage_f = (info.speed - tolerance)/BS*factor;
u16 damage = (u16)(damage_f+0.5);
if(lplayer->hp > damage)
lplayer->hp -= damage;
else
lplayer->hp = 0;
v3f lplayerpos = lplayer->getPosition();
ClientEnvEvent event;
event.type = CEE_PLAYER_DAMAGE;
event.player_damage.amount = damage;
event.player_damage.send_to_server = true;
m_client_event_queue.push_back(event);
// Apply physics
if(free_move == false && is_climbing == false)
{
// Gravity
v3f speed = lplayer->getSpeed();
if(lplayer->swimming_up == false)
speed.Y -= 9.81 * BS * dtime_part * 2;
// Water resistance
if(lplayer->in_water_stable || lplayer->in_water)
{
f32 max_down = 2.0*BS;
if(speed.Y < -max_down) speed.Y = -max_down;
f32 max = 2.5*BS;
if(speed.getLength() > max)
{
speed = speed / speed.getLength() * max;
}
}
lplayer->setSpeed(speed);
}
/*
Move the lplayer.
This also does collision detection.
*/
lplayer->move(dtime_part, *m_map, position_max_increment,
&player_collisions);
}
}
while(dtime_downcount > 0.001);
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
for(core::list<CollisionInfo>::Iterator
i = player_collisions.begin();
i != player_collisions.end(); i++)
{
CollisionInfo &info = *i;
if(info.t == COLLISION_FALL)
{
//f32 tolerance = BS*10; // 2 without damage
f32 tolerance = BS*12; // 3 without damage
f32 factor = 1;
if(info.speed > tolerance)
{
f32 damage_f = (info.speed - tolerance)/BS*factor;
u16 damage = (u16)(damage_f+0.5);
if(lplayer->hp > damage)
lplayer->hp -= damage;
else
lplayer->hp = 0;
ClientEnvEvent event;
event.type = CEE_PLAYER_DAMAGE;
event.player_damage.amount = damage;
event.player_damage.send_to_server = true;
m_client_event_queue.push_back(event);
}
}
}
}

View File

@@ -129,9 +129,7 @@ struct ABMWithState
ActiveBlockModifier *abm;
float timer;
ABMWithState(ActiveBlockModifier *abm_):
abm(abm_)
{}
ABMWithState(ActiveBlockModifier *abm_);
};
/*
@@ -261,18 +259,27 @@ 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 nodes inside a radius around a point
core::list<MapNode> getNodesInsideRadius(v3s16 pos, float radius);
// 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:

View File

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

View File

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

View File

@@ -29,6 +29,7 @@ class IRespawnInitiator
{
public:
virtual void respawn() = 0;
virtual ~IRespawnInitiator() {};
};
class GUIDeathScreen : public GUIModalMenu

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverobject.h"
#include "content_mapnode.h"
#include "content_sao.h"
#include "content_sao_item.h"
#include "environment.h"
#include "mapblock.h"
#include "player.h"
@@ -37,7 +38,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 +246,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 +311,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 +368,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 +567,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 +1057,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

View File

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

View File

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

View File

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

View File

@@ -82,6 +82,105 @@ scene::IAnimatedMesh* createCubeMesh(v3f scale)
return anim_mesh;
}
scene::IAnimatedMesh* createCubeMesh(v3f scale,core::aabbox3d<f32> box)
{
video::SColor c(255,255,255,255);
video::S3DVertex vertices[24] =
{
// Up
video::S3DVertex(box.MinEdge.X,box.MaxEdge.Y,box.MinEdge.Z, 0,1,0, c, 0,1),
video::S3DVertex(box.MinEdge.X,box.MaxEdge.Y,box.MaxEdge.Z, 0,1,0, c, 0,0),
video::S3DVertex(box.MaxEdge.X,box.MaxEdge.Y,box.MaxEdge.Z, 0,1,0, c, 1,0),
video::S3DVertex(box.MaxEdge.X,box.MaxEdge.Y,box.MinEdge.Z, 0,1,0, c, 1,1),
// Down
video::S3DVertex(box.MinEdge.X,box.MinEdge.Y,box.MinEdge.Z, 0,-1,0, c, 0,0),
video::S3DVertex(box.MaxEdge.X,box.MinEdge.Y,box.MinEdge.Z, 0,-1,0, c, 1,0),
video::S3DVertex(box.MaxEdge.X,box.MinEdge.Y,box.MaxEdge.Z, 0,-1,0, c, 1,1),
video::S3DVertex(box.MinEdge.X,box.MinEdge.Y,box.MaxEdge.Z, 0,-1,0, c, 0,1),
// Right
video::S3DVertex(box.MaxEdge.X,box.MinEdge.Y,box.MinEdge.Z, 1,0,0, c, 0,1),
video::S3DVertex(box.MaxEdge.X,box.MaxEdge.Y,box.MinEdge.Z, 1,0,0, c, 0,0),
video::S3DVertex(box.MaxEdge.X,box.MaxEdge.Y,box.MaxEdge.Z, 1,0,0, c, 1,0),
video::S3DVertex(box.MaxEdge.X,box.MinEdge.Y,box.MaxEdge.Z, 1,0,0, c, 1,1),
// Left
video::S3DVertex(box.MinEdge.X,box.MinEdge.Y,box.MinEdge.Z, -1,0,0, c, 1,1),
video::S3DVertex(box.MinEdge.X,box.MinEdge.Y,box.MaxEdge.Z, -1,0,0, c, 0,1),
video::S3DVertex(box.MinEdge.X,box.MaxEdge.Y,box.MaxEdge.Z, -1,0,0, c, 0,0),
video::S3DVertex(box.MinEdge.X,box.MaxEdge.Y,box.MinEdge.Z, -1,0,0, c, 1,0),
// Back
video::S3DVertex(box.MinEdge.X,box.MinEdge.Y,box.MaxEdge.Z, 0,0,1, c, 1,1),
video::S3DVertex(box.MaxEdge.X,box.MinEdge.Y,box.MaxEdge.Z, 0,0,1, c, 0,1),
video::S3DVertex(box.MaxEdge.X,box.MaxEdge.Y,box.MaxEdge.Z, 0,0,1, c, 0,0),
video::S3DVertex(box.MinEdge.X,box.MaxEdge.Y,box.MaxEdge.Z, 0,0,1, c, 1,0),
// Front
video::S3DVertex(box.MinEdge.X,box.MinEdge.Y,box.MinEdge.Z, 0,0,-1, c, 0,1),
video::S3DVertex(box.MinEdge.X,box.MaxEdge.Y,box.MinEdge.Z, 0,0,-1, c, 0,0),
video::S3DVertex(box.MaxEdge.X,box.MaxEdge.Y,box.MinEdge.Z, 0,0,-1, c, 1,0),
video::S3DVertex(box.MaxEdge.X,box.MinEdge.Y,box.MinEdge.Z, 0,0,-1, c, 1,1),
};
u16 indices[6] = {0,1,2,2,3,0};
scene::SMesh *mesh = new scene::SMesh();
for (u32 i=0; i<6; ++i)
{
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
buf->append(vertices + 4 * i, 4, indices, 6);
mesh->addMeshBuffer(buf);
buf->drop();
}
scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
mesh->drop();
scaleMesh(anim_mesh, scale); // also recalculates bounding box
return anim_mesh;
}
scene::IAnimatedMesh* createPlantMesh(v3f scale)
{
video::SColor c(255,255,255,255);
video::S3DVertex vertices[16] =
{
// Plane 1 Front
video::S3DVertex(-0.5,-0.5,-0.5, 0.5,0,-0.5, c, 0,1),
video::S3DVertex(-0.5,+0.5,-0.5, 0.5,0,-0.5, c, 0,0),
video::S3DVertex(+0.5,+0.5,+0.5, 0.5,0,-0.5, c, 1,0),
video::S3DVertex(+0.5,-0.5,+0.5, 0.5,0,-0.5, c, 1,1),
// Plane 1 Back
video::S3DVertex(+0.5,-0.5,+0.5, -0.5,0,0.5, c, 1,1),
video::S3DVertex(+0.5,+0.5,+0.5, -0.5,0,0.5, c, 1,0),
video::S3DVertex(-0.5,+0.5,-0.5, -0.5,0,0.5, c, 0,0),
video::S3DVertex(-0.5,-0.5,-0.5, -0.5,0,0.5, c, 0,1),
// Plane 2 Front
video::S3DVertex(-0.5,-0.5,+0.5, -0.5,0,-0.5, c, 1,1),
video::S3DVertex(-0.5,+0.5,+0.5, -0.5,0,-0.5, c, 1,0),
video::S3DVertex(+0.5,+0.5,-0.5, -0.5,0,-0.5, c, 0,0),
video::S3DVertex(+0.5,-0.5,-0.5, -0.5,0,-0.5, c, 0,1),
// Plane 2 Back
video::S3DVertex(+0.5,-0.5,-0.5, 0.5,0,0.5, c, 0,1),
video::S3DVertex(+0.5,+0.5,-0.5, 0.5,0,0.5, c, 0,0),
video::S3DVertex(-0.5,+0.5,+0.5, 0.5,0,0.5, c, 1,0),
video::S3DVertex(-0.5,-0.5,+0.5, 0.5,0,0.5, c, 1,1)
};
u16 indices[6] = {0,1,2,2,3,0};
scene::SMesh *mesh = new scene::SMesh();
for (u32 i=0; i<4; ++i)
{
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
buf->append(vertices + 4 * i, 4, indices, 6);
mesh->addMeshBuffer(buf);
buf->drop();
}
scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
mesh->drop();
scaleMesh(anim_mesh, scale); // also recalculates bounding box
return anim_mesh;
}
static scene::IAnimatedMesh* extrudeARGB(u32 twidth, u32 theight, u8 *data)
{
const s32 argb_wstep = 4 * twidth;

View File

@@ -31,6 +31,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
scene::IAnimatedMesh* createCubeMesh(v3f scale);
/*
Create a new cube mesh not linked to mapnode size.
Vertices are defined by given box.
The resulting mesh has 6 materials (up, down, right, left, back, front)
which must be defined by the caller.
*/
scene::IAnimatedMesh* createCubeMesh(v3f scale,core::aabbox3d<f32> box);
/*
Create a new extruded mesh from a texture.
Maximum bounding box is (+-scale.X/2, +-scale.Y/2, +-scale.Z).
@@ -41,6 +50,16 @@ scene::IAnimatedMesh* createCubeMesh(v3f scale);
scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture,
video::IVideoDriver *driver, v3f scale);
/*
Create a new plant style mesh.
Vertices are at (+-scale.X/2, +-scale.Y/2, +-scale.Z/2).
The resulting mesh has 4 materials (right, left, back, front)
which must be defined by the caller.
*/
scene::IAnimatedMesh* createPlantMesh(v3f scale);
/*
Multiplies each vertex coordinate by the specified scaling factors
(componentwise vector multiplication).

View File

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

View File

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

View File

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

View File

@@ -183,7 +183,8 @@ void Player::deSerialize(std::istream &is)
LocalPlayer::LocalPlayer(IGameDef *gamedef):
Player(gamedef),
m_sneak_node(32767,32767,32767),
m_sneak_node_exists(false)
m_sneak_node_exists(false),
m_linked(false)
{
// Initialize hp to 0, so that no hearts will be shown if server
// doesn't support health points

View File

@@ -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);
@@ -241,6 +251,13 @@ class LocalPlayer : public Player
PlayerControl control;
inline void Link(bool value) {
m_linked = value;
}
bool m_linked;
private:
// This is used for determining the sneaking range
v3s16 m_sneak_node;

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,53 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2012 sapier sapier at gmx dot net
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 "serverlinkableobject.h"
ServerLinkableObject::ServerLinkableObject() {
this->m_Linked = false;
}
ServerLinkableObject::~ServerLinkableObject() {}
bool ServerLinkableObject::linkEntity(ServerActiveObject* parent,v3f offset) {
//check if entity is in correct state
if (this->m_Linked == true) {
errorstream<<"ServerLinkableObject: link but object already linked!"<<std::endl;
return false;
}
this->m_Linked = true;
errorstream<<"ServerLinkableObject: try to send link message!"<<std::endl;
return sendLinkMsg(parent,offset);
}
bool ServerLinkableObject::unlinkEntity() {
//check if entity is in correct state
if (this->m_Linked == false) {
errorstream<<"ServerLinkableObject: unlink but object not linked!"<<std::endl;
return false;
}
this->m_Linked = false;
errorstream<<"ServerLinkableObject: try to send unlink message!"<<std::endl;
return sendUnlinkMsg();
}

View File

@@ -0,0 +1,49 @@
/*
Minetest-c55
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2012 sapier sapier at gmx dot net
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 SERVERLINKABLEOBJECT_H_
#define SERVERLINKABLEOBJECT_H_
#include <sstream>
#include <irrlichttypes.h>
#include "serverobject.h"
#include "content_object.h"
#include "log.h"
class ServerLinkableObject {
public:
ServerLinkableObject();
~ServerLinkableObject();
bool linkEntity(ServerActiveObject* parent,v3f offset);
bool unlinkEntity();
virtual bool sendLinkMsg(ServerActiveObject* parent,v3f offset) = 0;
virtual bool sendUnlinkMsg() = 0;
protected:
inline bool isLinked() { return m_Linked; }
private:
bool m_Linked;
};
#endif /* SERVERLINKABLEOBJECT_H_ */

View File

@@ -43,8 +43,8 @@ ServerActiveObject* ServerActiveObject::create(u8 type,
const std::string &data)
{
// Find factory function
core::map<u16, Factory>::Node *n;
n = m_types.find(type);
core::map<u8, Factory>::Node *n;
n = ServerActiveObject::getTypes().find(type);
if(n == NULL)
{
// If factory is not found, just return.
@@ -58,13 +58,13 @@ ServerActiveObject* ServerActiveObject::create(u8 type,
return object;
}
void ServerActiveObject::registerType(u16 type, Factory f)
void ServerActiveObject::registerType(u8 type, Factory f)
{
core::map<u16, Factory>::Node *n;
n = m_types.find(type);
core::map<u8, Factory>::Node *n;
n = ServerActiveObject::getTypes().find(type);
if(n)
return;
m_types.insert(type, f);
ServerActiveObject::getTypes().insert(type, f);
}
void ServerActiveObject::getWieldDiggingProperties(ToolDiggingProperties *dst)

View File

@@ -200,14 +200,17 @@ class ServerActiveObject : public ActiveObject
typedef ServerActiveObject* (*Factory)
(ServerEnvironment *env, v3f pos,
const std::string &data);
static void registerType(u16 type, Factory f);
static void registerType(u8 type, Factory f);
ServerEnvironment *m_env;
v3f m_base_position;
private:
// Used for creating objects based on type
static core::map<u16, Factory> m_types;
static core::map<u8, Factory>& getTypes()
{
static core::map<u8, Factory> types;
return types;
}
};
#endif

View File

@@ -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,16 +96,22 @@ bool ServerRemotePlayer::unlimitedTransferDistance() const
void ServerRemotePlayer::step(float dtime, bool send_recommended)
{
m_time_from_last_punch += dtime;
if(send_recommended == false)
return;
if(isLinked())
return;
if(m_position_not_sent)
{
m_position_not_sent = false;
std::ostringstream os(std::ios::binary);
// command (0 = update position)
writeU8(os, 0);
writeU8(os,AO_Message_type::SetPosition );
// pos
writeV3F1000(os, getPosition());
// yaw
@@ -157,13 +166,18 @@ 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)
writeU8(os, 1);
writeU8(os, AO_Message_type::Punched);
// damage
writeS16(os, hitprop.hp);
// create message and add to list
@@ -313,4 +327,24 @@ s16 ServerRemotePlayer::getHP()
return hp;
}
bool ServerRemotePlayer::sendLinkMsg(ServerActiveObject* parent,v3f offset) {
std::ostringstream os(std::ios::binary);
writeU8(os, AO_Message_type::Link);
// parameters
writeU16(os, parent->getId());
writeV3F1000(os, offset);
// create message and add to list
ActiveObjectMessage aom(getId(), true, os.str());
m_messages_out.push_back(aom);
return true;
}
bool ServerRemotePlayer::sendUnlinkMsg() {
std::ostringstream os(std::ios::binary);
writeU8(os, AO_Message_type::UnLink);
// create message and add to list
ActiveObjectMessage aom(getId(), true, os.str());
m_messages_out.push_back(aom);
return true;
}

View File

@@ -22,13 +22,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "player.h"
#include "serverobject.h"
#include "serverlinkableobject.h"
#include "content_object.h" // Object type IDs
/*
Player on the server
*/
class ServerRemotePlayer : public Player, public ServerActiveObject
class ServerRemotePlayer : public Player, public ServerActiveObject, public ServerLinkableObject
{
public:
ServerRemotePlayer(ServerEnvironment *env);
@@ -74,7 +75,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 +95,11 @@ 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;
bool sendLinkMsg(ServerActiveObject* parent,v3f offset);
bool sendUnlinkMsg();
private:
bool m_position_not_sent;

View File

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

View File

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