aboutsummaryrefslogtreecommitdiff
path: root/src/server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server.cpp')
-rw-r--r--src/server.cpp1457
1 files changed, 719 insertions, 738 deletions
diff --git a/src/server.cpp b/src/server.cpp
index 63172e955..70638a0a6 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -45,6 +45,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h"
#include "tooldef.h"
#include "craftdef.h"
+#include "craftitemdef.h"
#include "mapgen.h"
#include "content_abm.h"
@@ -1033,6 +1034,7 @@ Server::Server(
m_toolmgr(createToolDefManager()),
m_nodedef(createNodeDefManager()),
m_craftdef(createCraftDefManager()),
+ m_craftitemdef(createCraftItemDefManager()),
m_thread(this),
m_emergethread(this),
m_time_counter(0),
@@ -1206,6 +1208,8 @@ Server::~Server()
delete m_toolmgr;
delete m_nodedef;
+ delete m_craftdef;
+ delete m_craftitemdef;
// Deinitialize scripting
infostream<<"Server: Deinitializing scripting"<<std::endl;
@@ -1396,7 +1400,8 @@ void Server::AsyncRunStep()
{
RemoteClient *client = i.getNode()->getValue();
ServerRemotePlayer *player =
- (ServerRemotePlayer*)m_env->getPlayer(client->peer_id);
+ static_cast<ServerRemotePlayer*>
+ (m_env->getPlayer(client->peer_id));
if(player==NULL)
continue;
player->m_last_good_position_age += dtime;
@@ -2240,6 +2245,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Send node definitions
SendNodeDef(m_con, peer_id, m_nodedef);
+ // Send CraftItem definitions
+ SendCraftItemDef(m_con, peer_id, m_craftitemdef);
+
// Send textures
SendTextures(peer_id);
@@ -2420,745 +2428,23 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
{
- if(datasize < 7)
- return;
-
- if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
- return;
-
- /*
- length: 7
- [0] u16 command
- [2] u8 button (0=left, 1=right)
- [3] u16 id
- [5] u16 item
- */
- u8 button = readU8(&data[2]);
- u16 id = readS16(&data[3]);
- u16 item_i = readU16(&data[5]);
-
- ServerActiveObject *obj = m_env->getActiveObject(id);
-
- if(obj == NULL)
- {
- infostream<<"Server: CLICK_ACTIVEOBJECT: object not found"
- <<std::endl;
- return;
- }
-
- // Skip if object has been removed
- if(obj->m_removed)
- return;
-
- //TODO: Check that object is reasonably close
-
- // Get ServerRemotePlayer
- ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
-
- // Update wielded item
- srp->wieldItem(item_i);
-
- // Left click, pick/punch
- if(button == 0)
- {
- actionstream<<player->getName()<<" punches object "
- <<obj->getId()<<std::endl;
-
- // Do stuff
- obj->punch(srp);
-
-#if 0
- /*
- Try creating inventory item
- */
- InventoryItem *item = obj->createPickedUpItem();
-
- if(item)
- {
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist != NULL)
- {
- actionstream<<player->getName()<<" picked up "
- <<item->getName()<<std::endl;
- if(g_settings->getBool("creative_mode") == false)
- {
- // Skip if inventory has no free space
- if(ilist->roomForItem(item) == false)
- {
- infostream<<"Player inventory has no free space"<<std::endl;
- return;
- }
-
- // Add to inventory and send inventory
- ilist->addItem(item);
- UpdateCrafting(player->peer_id);
- SendInventory(player->peer_id);
- }
-
- // Remove object from environment
- obj->m_removed = true;
- }
- }
- else
- {
- /*
- Item cannot be picked up. Punch it instead.
- */
-
- actionstream<<player->getName()<<" punches object "
- <<obj->getId()<<std::endl;
-
- ToolItem *titem = NULL;
- std::string toolname = "";
-
- InventoryList *mlist = player->inventory.getList("main");
- if(mlist != NULL)
- {
- InventoryItem *item = mlist->getItem(item_i);
- if(item && (std::string)item->getName() == "ToolItem")
- {
- titem = (ToolItem*)item;
- toolname = titem->getToolName();
- }
- }
-
- v3f playerpos = player->getPosition();
- v3f objpos = obj->getBasePosition();
- v3f dir = (objpos - playerpos).normalize();
-
- u16 wear = obj->punch(toolname, dir, player->getName());
-
- if(titem)
- {
- bool weared_out = titem->addWear(wear);
- if(weared_out)
- mlist->deleteItem(item_i);
- SendInventory(player->peer_id);
- }
- }
-#endif
- }
- // Right click, do something with object
- if(button == 1)
- {
- actionstream<<player->getName()<<" right clicks object "
- <<obj->getId()<<std::endl;
-
- // Do stuff
- obj->rightClick(srp);
- }
-
- /*
- Update player state to client
- */
- SendPlayerHP(player);
- UpdateCrafting(player->peer_id);
- SendInventory(player->peer_id);
+ infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
+ return;
}
else if(command == TOSERVER_GROUND_ACTION)
{
- if(datasize < 17)
- return;
- /*
- length: 17
- [0] u16 command
- [2] u8 action
- [3] v3s16 nodepos_undersurface
- [9] v3s16 nodepos_abovesurface
- [15] u16 item
- actions:
- 0: start digging
- 1: place block
- 2: stop digging (all parameters ignored)
- 3: digging completed
- */
- u8 action = readU8(&data[2]);
- v3s16 p_under;
- p_under.X = readS16(&data[3]);
- p_under.Y = readS16(&data[5]);
- p_under.Z = readS16(&data[7]);
- v3s16 p_over;
- p_over.X = readS16(&data[9]);
- p_over.Y = readS16(&data[11]);
- p_over.Z = readS16(&data[13]);
- u16 item_i = readU16(&data[15]);
-
- ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
-
- /*
- Check that target is reasonably close
- */
- if(action != 2) // action 2 has always position (0,0,0)
- {
- v3f np_f = intToFloat(p_under, BS);
- float max_d = BS * 10; // Just some large enough value
- float d = srp->m_last_good_position.getDistanceFrom(np_f);
- if(d > max_d){
- actionstream<<"Player "<<player->getName()
- <<" tried to access node from too far: "
- <<"d="<<d<<", max_d="<<max_d
- <<". ignoring."<<std::endl;
- // Re-send block to revert change on client-side
- RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(p_under);
- client->SetBlockNotSent(blockpos);
- // Do nothing else
- return;
- }
- }
-
- /*
- 0: start digging
- */
- if(action == 0)
- {
- /*
- NOTE: This can be used in the future to check if
- somebody is cheating, by checking the timing.
- */
- bool cannot_punch_node = false;
-
- MapNode n(CONTENT_IGNORE);
-
- try
- {
- n = m_env->getMap().getNode(p_under);
- }
- catch(InvalidPositionException &e)
- {
- infostream<<"Server: Not punching: Node not found."
- <<" Adding block to emerge queue."
- <<std::endl;
- m_emerge_queue.addBlock(peer_id,
- getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
- cannot_punch_node = true;
- }
-
- if(cannot_punch_node)
- return;
-
- /*
- Run script hook
- */
- scriptapi_environment_on_punchnode(m_lua, p_under, n, srp);
-
- } // action == 0
-
- /*
- 2: stop digging
- */
- else if(action == 2)
- {
-#if 0
- RemoteClient *client = getClient(peer_id);
- JMutexAutoLock digmutex(client->m_dig_mutex);
- client->m_dig_tool_item = -1;
-#endif
- }
-
- /*
- 3: Digging completed
- */
- else if(action == 3)
- {
- // Mandatory parameter; actually used for nothing
- core::map<v3s16, MapBlock*> modified_blocks;
-
- content_t material = CONTENT_IGNORE;
- u8 mineral = MINERAL_NONE;
-
- bool cannot_remove_node = false;
-
- MapNode n(CONTENT_IGNORE);
- try
- {
- n = m_env->getMap().getNode(p_under);
- // Get mineral
- mineral = n.getMineral(m_nodedef);
- // Get material at position
- material = n.getContent();
- // If not yet cancelled
- if(cannot_remove_node == false)
- {
- // If it's not diggable, do nothing
- if(m_nodedef->get(material).diggable == false)
- {
- infostream<<"Server: Not finishing digging: "
- <<"Node not diggable"
- <<std::endl;
- cannot_remove_node = true;
- }
- }
- // If not yet cancelled
- if(cannot_remove_node == false)
- {
- // Get node metadata
- NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
- if(meta && meta->nodeRemovalDisabled() == true)
- {
- infostream<<"Server: Not finishing digging: "
- <<"Node metadata disables removal"
- <<std::endl;
- cannot_remove_node = true;
- }
- }
- }
- catch(InvalidPositionException &e)
- {
- infostream<<"Server: Not finishing digging: Node not found."
- <<" Adding block to emerge queue."
- <<std::endl;
- m_emerge_queue.addBlock(peer_id,
- getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
- cannot_remove_node = true;
- }
-
- // Make sure the player is allowed to do it
- if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
- {
- infostream<<"Player "<<player->getName()<<" cannot remove node"
- <<" because privileges are "<<getPlayerPrivs(player)
- <<std::endl;
- cannot_remove_node = true;
- }
-
- /*
- If node can't be removed, set block to be re-sent to
- client and quit.
- */
- if(cannot_remove_node)
- {
- infostream<<"Server: Not finishing digging."<<std::endl;
-
- // Client probably has wrong data.
- // Set block not sent, so that client will get
- // a valid one.
- infostream<<"Client "<<peer_id<<" tried to dig "
- <<"node; but node cannot be removed."
- <<" setting MapBlock not sent."<<std::endl;
- RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(p_under);
- client->SetBlockNotSent(blockpos);
-
- return;
- }
-
- actionstream<<player->getName()<<" digs "<<PP(p_under)
- <<", gets material "<<(int)material<<", mineral "
- <<(int)mineral<<std::endl;
-
- /*
- Send the removal to all close-by players.
- - If other player is close, send REMOVENODE
- - Otherwise set blocks not sent
- */
- core::list<u16> far_players;
- sendRemoveNode(p_under, peer_id, &far_players, 30);
-
- /*
- Update and send inventory
- */
-
- if(g_settings->getBool("creative_mode") == false)
- {
- /*
- Wear out tool
- */
- InventoryList *mlist = player->inventory.getList("main");
- if(mlist != NULL)
- {
- InventoryItem *item = mlist->getItem(item_i);
- if(item && (std::string)item->getName() == "ToolItem")
- {
- ToolItem *titem = (ToolItem*)item;
- std::string toolname = titem->getToolName();
-
- // Get digging properties for material and tool
- ToolDiggingProperties tp =
- m_toolmgr->getDiggingProperties(toolname);
- DiggingProperties prop =
- getDiggingProperties(material, &tp, m_nodedef);
-
- if(prop.diggable == false)
- {
- infostream<<"Server: WARNING: Player digged"
- <<" with impossible material + tool"
- <<" combination"<<std::endl;
- }
-
- bool weared_out = titem->addWear(prop.wear);
-
- if(weared_out)
- {
- mlist->deleteItem(item_i);
- }
- }
- }
-
- /*
- Add dug item to inventory
- */
-
- InventoryItem *item = NULL;
-
- if(mineral != MINERAL_NONE)
- item = getDiggedMineralItem(mineral, this);
-
- // If not mineral
- if(item == NULL)
- {
- const std::string &dug_s = m_nodedef->get(material).dug_item;
- if(dug_s != "")
- {
- std::istringstream is(dug_s, std::ios::binary);
- item = InventoryItem::deSerialize(is, this);
- }
- }
-
- if(item != NULL)
- {
- // Add a item to inventory
- player->inventory.addItem("main", item);
-
- // Send inventory
- UpdateCrafting(player->peer_id);
- SendInventory(player->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;
- if(extra_dug_s != "" && extra_rarity != 0
- && myrand() % extra_rarity == 0)
- {
- std::istringstream is(extra_dug_s, std::ios::binary);
- item = InventoryItem::deSerialize(is, this);
- }
- }
-
- if(item != NULL)
- {
- // Add a item to inventory
- player->inventory.addItem("main", item);
-
- // Send inventory
- UpdateCrafting(player->peer_id);
- SendInventory(player->peer_id);
- }
- }
-
- /*
- Remove the node
- (this takes some time so it is done after the quick stuff)
- */
- {
- MapEditEventIgnorer ign(&m_ignore_map_edit_events);
-
- m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
- }
- /*
- Set blocks not sent to far players
- */
- for(core::list<u16>::Iterator
- i = far_players.begin();
- i != far_players.end(); i++)
- {
- u16 peer_id = *i;
- RemoteClient *client = getClient(peer_id);
- if(client==NULL)
- continue;
- client->SetBlocksNotSent(modified_blocks);
- }
-
- /*
- Run script hook
- */
- scriptapi_environment_on_dignode(m_lua, p_under, n, srp);
- }
-
- /*
- 1: place block
- */
- else if(action == 1)
- {
-
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist == NULL)
- return;
-
- // Get item
- InventoryItem *item = ilist->getItem(item_i);
-
- // If there is no item, it is not possible to add it anywhere
- if(item == NULL)
- return;
-
- /*
- Handle material items
- */
- if(std::string("MaterialItem") == item->getName())
- {
- try{
- // Don't add a node if this is not a free space
- MapNode n2 = m_env->getMap().getNode(p_over);
- bool no_enough_privs =
- ((getPlayerPrivs(player) & PRIV_BUILD)==0);
- if(no_enough_privs)
- infostream<<"Player "<<player->getName()<<" cannot add node"
- <<" because privileges are "<<getPlayerPrivs(player)
- <<std::endl;
-
- if(m_nodedef->get(n2).buildable_to == false
- || no_enough_privs)
- {
- // Client probably has wrong data.
- // Set block not sent, so that client will get
- // a valid one.
- infostream<<"Client "<<peer_id<<" tried to place"
- <<" node in invalid position; setting"
- <<" MapBlock not sent."<<std::endl;
- RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(p_over);
- client->SetBlockNotSent(blockpos);
- return;
- }
- }
- catch(InvalidPositionException &e)
- {
- infostream<<"Server: Ignoring ADDNODE: Node not found"
- <<" Adding block to emerge queue."
- <<std::endl;
- m_emerge_queue.addBlock(peer_id,
- getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
- return;
- }
-
- // Reset build time counter
- getClient(peer_id)->m_time_from_building = 0.0;
-
- // Create node data
- MaterialItem *mitem = (MaterialItem*)item;
- MapNode n;
- n.setContent(mitem->getMaterial());
-
- actionstream<<player->getName()<<" places material "
- <<(int)mitem->getMaterial()
- <<" at "<<PP(p_under)<<std::endl;
-
- // Calculate direction for wall mounted stuff
- if(m_nodedef->get(n).wall_mounted)
- n.param2 = packDir(p_under - p_over);
-
- // Calculate the direction for furnaces and chests and stuff
- if(m_nodedef->get(n).param_type == CPT_FACEDIR_SIMPLE)
- {
- v3f playerpos = player->getPosition();
- v3f blockpos = intToFloat(p_over, BS) - playerpos;
- blockpos = blockpos.normalize();
- n.param1 = 0;
- if (fabs(blockpos.X) > fabs(blockpos.Z)) {
- if (blockpos.X < 0)
- n.param1 = 3;
- else
- n.param1 = 1;
- } else {
- if (blockpos.Z < 0)
- n.param1 = 2;
- else
- n.param1 = 0;
- }
- }
-
- /*
- Send to all close-by players
- */
- core::list<u16> far_players;
- sendAddNode(p_over, n, 0, &far_players, 30);
-
- /*
- Handle inventory
- */
- InventoryList *ilist = player->inventory.getList("main");
- if(g_settings->getBool("creative_mode") == false && ilist)
- {
- // Remove from inventory and send inventory
- if(mitem->getCount() == 1)
- ilist->deleteItem(item_i);
- else
- mitem->remove(1);
- // Send inventory
- UpdateCrafting(peer_id);
- SendInventory(peer_id);
- }
-
- /*
- Add node.
-
- This takes some time so it is done after the quick stuff
- */
- core::map<v3s16, MapBlock*> modified_blocks;
- {
- MapEditEventIgnorer ign(&m_ignore_map_edit_events);
-
- std::string p_name = std::string(player->getName());
- m_env->getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
- }
- /*
- Set blocks not sent to far players
- */
- for(core::list<u16>::Iterator
- i = far_players.begin();
- i != far_players.end(); i++)
- {
- u16 peer_id = *i;
- RemoteClient *client = getClient(peer_id);
- if(client==NULL)
- continue;
- client->SetBlocksNotSent(modified_blocks);
- }
-
- /*
- Run script hook
- */
- scriptapi_environment_on_placenode(m_lua, p_over, n, srp);
-
- /*
- Calculate special events
- */
-
- /*if(n.d == LEGN(m_nodedef, "CONTENT_MESE"))
- {
- u32 count = 0;
- for(s16 z=-1; z<=1; z++)
- for(s16 y=-1; y<=1; y++)
- for(s16 x=-1; x<=1; x++)
- {
-
- }
- }*/
- }
- /*
- Place other item (not a block)
- */
- else
- {
- v3s16 blockpos = getNodeBlockPos(p_over);
-
- /*
- Check that the block is loaded so that the item
- can properly be added to the static list too
- */
- MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
- if(block==NULL)
- {
- infostream<<"Error while placing object: "
- "block not found"<<std::endl;
- return;
- }
-
- /*
- If in creative mode, item dropping is disabled unless
- player has build privileges
- */
- if(g_settings->getBool("creative_mode") &&
- (getPlayerPrivs(player) & PRIV_BUILD) == 0)
- {
- infostream<<"Not allowing player to drop item: "
- "creative mode and no build privs"<<std::endl;
- return;
- }
-
- // Calculate a position for it
- v3f pos = intToFloat(p_over, BS);
- //pos.Y -= BS*0.45;
- /*pos.Y -= BS*0.25; // let it drop a bit
- // Randomize a bit
- pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
- pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;*/
-
- /*
- Create the object
- */
- ServerActiveObject *obj = item->createSAO(m_env, pos);
-
- if(obj == NULL)
- {
- infostream<<"WARNING: item resulted in NULL object, "
- <<"not placing onto map"
- <<std::endl;
- }
- else
- {
- actionstream<<player->getName()<<" places "<<item->getName()
- <<" at "<<PP(p_over)<<std::endl;
-
- // Add the object to the environment
- m_env->addActiveObject(obj);
-
- infostream<<"Placed object"<<std::endl;
-
- if(g_settings->getBool("creative_mode") == false)
- {
- // Delete the right amount of items from the slot
- u16 dropcount = item->getDropCount();
-
- // Delete item if all gone
- if(item->getCount() <= dropcount)
- {
- if(item->getCount() < dropcount)
- infostream<<"WARNING: Server: dropped more items"
- <<" than the slot contains"<<std::endl;
-
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist)
- // Remove from inventory and send inventory
- ilist->deleteItem(item_i);
- }
- // Else decrement it
- else
- item->remove(dropcount);
-
- // Send inventory
- UpdateCrafting(peer_id);
- SendInventory(peer_id);
- }
- }
- }
-
- } // action == 1
+ infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
+ return;
- /*
- Catch invalid actions
- */
- else
- {
- infostream<<"WARNING: Server: Invalid action "
- <<action<<std::endl;
- }
}
-#if 0
else if(command == TOSERVER_RELEASE)
{
- if(datasize < 3)
- return;
- /*
- length: 3
- [0] u16 command
- [2] u8 button
- */
- infostream<<"TOSERVER_RELEASE ignored"<<std::endl;
+ infostream<<"Server: RELEASE not supported anymore"<<std::endl;
+ return;
}
-#endif
else if(command == TOSERVER_SIGNTEXT)
{
- infostream<<"Server: TOSERVER_SIGNTEXT not supported anymore"
+ infostream<<"Server: SIGNTEXT not supported anymore"
<<std::endl;
return;
}
@@ -3367,12 +2653,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Feed action to player inventory
a->apply(&c, this, m_env);
}
- else
- {
- // Send inventory
- UpdateCrafting(player->peer_id);
- SendInventory(player->peer_id);
- }
// Eat the action
delete a;
@@ -3605,6 +2885,674 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
actionstream<<player->getName()<<" respawns at "
<<PP(player->getPosition()/BS)<<std::endl;
}
+ else if(command == TOSERVER_INTERACT)
+ {
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ /*
+ [0] u16 command
+ [2] u8 action
+ [3] u16 item
+ [5] u32 length of the next item
+ [9] serialized PointedThing
+ actions:
+ 0: start digging (from undersurface) or use
+ 1: stop digging (all parameters ignored)
+ 2: digging completed
+ 3: place block or item (to abovesurface)
+ 4: use item
+ */
+ u8 action = readU8(is);
+ u16 item_i = readU16(is);
+ std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
+ PointedThing pointed;
+ pointed.deSerialize(tmp_is);
+
+ infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<<item_i<<", pointed="<<pointed.dump()<<std::endl;
+
+ ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
+ v3f player_pos = srp->m_last_good_position;
+
+ // Update wielded item
+ srp->wieldItem(item_i);
+
+ // Get pointed to node (undefined if not POINTEDTYPE_NODE)
+ v3s16 p_under = pointed.node_undersurface;
+ v3s16 p_above = pointed.node_abovesurface;
+
+ // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
+ ServerActiveObject *pointed_object = NULL;
+ if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ pointed_object = m_env->getActiveObject(pointed.object_id);
+ if(pointed_object == NULL)
+ {
+ infostream<<"TOSERVER_INTERACT: "
+ "pointed object is NULL"<<std::endl;
+ return;
+ }
+
+ }
+
+ /*
+ Check that target is reasonably close
+ (only when digging or placing things)
+ */
+ if(action == 0 || action == 2 || action == 3)
+ {
+ v3f pointed_pos = player_pos;
+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ pointed_pos = intToFloat(p_under, BS);
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ pointed_pos = pointed_object->getBasePosition();
+ }
+
+ float d = player_pos.getDistanceFrom(pointed_pos);
+ float max_d = BS * 10; // Just some large enough value
+ if(d > max_d){
+ actionstream<<"Player "<<player->getName()
+ <<" tried to access "<<pointed.dump()
+ <<" from too far: "
+ <<"d="<<d<<", max_d="<<max_d
+ <<". ignoring."<<std::endl;
+ // Re-send block to revert change on client-side
+ RemoteClient *client = getClient(peer_id);
+ v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos, BS));
+ client->SetBlockNotSent(blockpos);
+ // Do nothing else
+ return;
+ }
+ }
+
+ /*
+ Make sure the player is allowed to do it
+ */
+ bool build_priv = (getPlayerPrivs(player) & PRIV_BUILD) != 0;
+ if(!build_priv)
+ {
+ infostream<<"Ignoring interaction from player "<<player->getName()
+ <<" because privileges are "<<getPlayerPrivs(player)
+ <<std::endl;
+ // NOTE: no return; here, fall through
+ }
+
+ /*
+ 0: start digging or punch object
+ */
+ if(action == 0)
+ {
+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ /*
+ NOTE: This can be used in the future to check if
+ somebody is cheating, by checking the timing.
+ */
+ bool cannot_punch_node = !build_priv;
+
+ MapNode n(CONTENT_IGNORE);
+
+ try
+ {
+ n = m_env->getMap().getNode(p_under);
+ }
+ catch(InvalidPositionException &e)
+ {
+ infostream<<"Server: Not punching: Node not found."
+ <<" Adding block to emerge queue."
+ <<std::endl;
+ m_emerge_queue.addBlock(peer_id,
+ getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
+ cannot_punch_node = true;
+ }
+
+ if(cannot_punch_node)
+ return;
+
+ /*
+ Run script hook
+ */
+ scriptapi_environment_on_punchnode(m_lua, p_under, n, srp);
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ if(!build_priv)
+ return;
+
+ // Skip if object has been removed
+ if(pointed_object->m_removed)
+ return;
+
+ actionstream<<player->getName()<<" punches object "
+ <<pointed.object_id<<std::endl;
+
+ // Do stuff
+ pointed_object->punch(srp);
+ }
+
+ } // action == 0
+
+ /*
+ 1: stop digging
+ */
+ else if(action == 1)
+ {
+ } // action == 1
+
+ /*
+ 2: Digging completed
+ */
+ else if(action == 2)
+ {
+ // Only complete digging of nodes
+ if(pointed.type != POINTEDTHING_NODE)
+ return;
+
+ // Mandatory parameter; actually used for nothing
+ core::map<v3s16, MapBlock*> modified_blocks;
+
+ content_t material = CONTENT_IGNORE;
+ u8 mineral = MINERAL_NONE;
+
+ bool cannot_remove_node = !build_priv;
+
+ MapNode n(CONTENT_IGNORE);
+ try
+ {
+ n = m_env->getMap().getNode(p_under);
+ // Get mineral
+ mineral = n.getMineral(m_nodedef);
+ // Get material at position
+ material = n.getContent();
+ // If not yet cancelled
+ if(cannot_remove_node == false)
+ {
+ // If it's not diggable, do nothing
+ if(m_nodedef->get(material).diggable == false)
+ {
+ infostream<<"Server: Not finishing digging: "
+ <<"Node not diggable"
+ <<std::endl;
+ cannot_remove_node = true;
+ }
+ }
+ // If not yet cancelled
+ if(cannot_remove_node == false)
+ {
+ // Get node metadata
+ NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
+ if(meta && meta->nodeRemovalDisabled() == true)
+ {
+ infostream<<"Server: Not finishing digging: "
+ <<"Node metadata disables removal"
+ <<std::endl;
+ cannot_remove_node = true;
+ }
+ }
+ }
+ catch(InvalidPositionException &e)
+ {
+ infostream<<"Server: Not finishing digging: Node not found."
+ <<" Adding block to emerge queue."
+ <<std::endl;
+ m_emerge_queue.addBlock(peer_id,
+ getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
+ cannot_remove_node = true;
+ }
+
+ /*
+ If node can't be removed, set block to be re-sent to
+ client and quit.
+ */
+ if(cannot_remove_node)
+ {
+ infostream<<"Server: Not finishing digging."<<std::endl;
+
+ // Client probably has wrong data.
+ // Set block not sent, so that client will get
+ // a valid one.
+ infostream<<"Client "<<peer_id<<" tried to dig "
+ <<"node; but node cannot be removed."
+ <<" setting MapBlock not sent."<<std::endl;
+ RemoteClient *client = getClient(peer_id);
+ v3s16 blockpos = getNodeBlockPos(p_under);
+ client->SetBlockNotSent(blockpos);
+
+ return;
+ }
+
+ actionstream<<player->getName()<<" digs "<<PP(p_under)
+ <<", gets material "<<(int)material<<", mineral "
+ <<(int)mineral<<std::endl;
+
+ /*
+ Send the removal to all close-by players.
+ - If other player is close, send REMOVENODE
+ - Otherwise set blocks not sent
+ */
+ core::list<u16> far_players;
+ sendRemoveNode(p_under, peer_id, &far_players, 30);
+
+ /*
+ Update and send inventory
+ */
+
+ if(g_settings->getBool("creative_mode") == false)
+ {
+ /*
+ Wear out tool
+ */
+ InventoryList *mlist = player->inventory.getList("main");
+ if(mlist != NULL)
+ {
+ InventoryItem *item = mlist->getItem(item_i);
+ if(item && (std::string)item->getName() == "ToolItem")
+ {
+ ToolItem *titem = (ToolItem*)item;
+ std::string toolname = titem->getToolName();
+
+ // Get digging properties for material and tool
+ ToolDiggingProperties tp =
+ m_toolmgr->getDiggingProperties(toolname);
+ DiggingProperties prop =
+ getDiggingProperties(material, &tp, m_nodedef);
+
+ if(prop.diggable == false)
+ {
+ infostream<<"Server: WARNING: Player digged"
+ <<" with impossible material + tool"
+ <<" combination"<<std::endl;
+ }
+
+ bool weared_out = titem->addWear(prop.wear);
+
+ if(weared_out)
+ {
+ mlist->deleteItem(item_i);
+ }
+ }
+ }
+
+ /*
+ Add dug item to inventory
+ */
+
+ InventoryItem *item = NULL;
+
+ if(mineral != MINERAL_NONE)
+ item = getDiggedMineralItem(mineral, this);
+
+ // If not mineral
+ if(item == NULL)
+ {
+ const std::string &dug_s = m_nodedef->get(material).dug_item;
+ if(dug_s != "")
+ {
+ std::istringstream is(dug_s, std::ios::binary);
+ item = InventoryItem::deSerialize(is, this);
+ }
+ }
+
+ if(item != NULL)
+ {
+ // Add a item to inventory
+ player->inventory.addItem("main", item);
+ }
+
+ 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;
+ if(extra_dug_s != "" && extra_rarity != 0
+ && myrand() % extra_rarity == 0)
+ {
+ std::istringstream is(extra_dug_s, std::ios::binary);
+ item = InventoryItem::deSerialize(is, this);
+ }
+ }
+
+ if(item != NULL)
+ {
+ // Add a item to inventory
+ player->inventory.addItem("main", item);
+ }
+ }
+
+ /*
+ Remove the node
+ (this takes some time so it is done after the quick stuff)
+ */
+ {
+ MapEditEventIgnorer ign(&m_ignore_map_edit_events);
+
+ m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
+ }
+ /*
+ Set blocks not sent to far players
+ */
+ for(core::list<u16>::Iterator
+ i = far_players.begin();
+ i != far_players.end(); i++)
+ {
+ u16 peer_id = *i;
+ RemoteClient *client = getClient(peer_id);
+ if(client==NULL)
+ continue;
+ client->SetBlocksNotSent(modified_blocks);
+ }
+
+ /*
+ Run script hook
+ */
+ scriptapi_environment_on_dignode(m_lua, p_under, n, srp);
+ } // action == 2
+
+ /*
+ 3: place block or right-click object
+ */
+ else if(action == 3)
+ {
+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ InventoryList *ilist = player->inventory.getList("main");
+ if(ilist == NULL)
+ return;
+
+ // Get item
+ InventoryItem *item = ilist->getItem(item_i);
+
+ // If there is no item, it is not possible to add it anywhere
+ if(item == NULL)
+ return;
+
+ /*
+ Handle material items
+ */
+ if(std::string("MaterialItem") == item->getName())
+ {
+ bool cannot_place_node = !build_priv;
+
+ try{
+ // Don't add a node if this is not a free space
+ MapNode n2 = m_env->getMap().getNode(p_above);
+ if(m_nodedef->get(n2).buildable_to == false)
+ {
+ infostream<<"Client "<<peer_id<<" tried to place"
+ <<" node in invalid position."<<std::endl;
+ cannot_place_node = true;
+ }
+ }
+ catch(InvalidPositionException &e)
+ {
+ infostream<<"Server: Ignoring ADDNODE: Node not found"
+ <<" Adding block to emerge queue."
+ <<std::endl;
+ m_emerge_queue.addBlock(peer_id,
+ getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
+ cannot_place_node = true;
+ }
+
+ if(cannot_place_node)
+ {
+ // Client probably has wrong data.
+ // Set block not sent, so that client will get
+ // a valid one.
+ RemoteClient *client = getClient(peer_id);
+ v3s16 blockpos = getNodeBlockPos(p_above);
+ client->SetBlockNotSent(blockpos);
+ return;
+ }
+
+ // Reset build time counter
+ getClient(peer_id)->m_time_from_building = 0.0;
+
+ // Create node data
+ MaterialItem *mitem = (MaterialItem*)item;
+ MapNode n;
+ n.setContent(mitem->getMaterial());
+
+ actionstream<<player->getName()<<" places material "
+ <<(int)mitem->getMaterial()
+ <<" at "<<PP(p_under)<<std::endl;
+
+ // Calculate direction for wall mounted stuff
+ if(m_nodedef->get(n).wall_mounted)
+ n.param2 = packDir(p_under - p_above);
+
+ // Calculate the direction for furnaces and chests and stuff
+ if(m_nodedef->get(n).param_type == CPT_FACEDIR_SIMPLE)
+ {
+ v3f playerpos = player->getPosition();
+ v3f blockpos = intToFloat(p_above, BS) - playerpos;
+ blockpos = blockpos.normalize();
+ n.param1 = 0;
+ if (fabs(blockpos.X) > fabs(blockpos.Z)) {
+ if (blockpos.X < 0)
+ n.param1 = 3;
+ else
+ n.param1 = 1;
+ } else {
+ if (blockpos.Z < 0)
+ n.param1 = 2;
+ else
+ n.param1 = 0;
+ }
+ }
+
+ /*
+ Send to all close-by players
+ */
+ core::list<u16> far_players;
+ sendAddNode(p_above, n, 0, &far_players, 30);
+
+ /*
+ Handle inventory
+ */
+ InventoryList *ilist = player->inventory.getList("main");
+ if(g_settings->getBool("creative_mode") == false && ilist)
+ {
+ // Remove from inventory and send inventory
+ if(mitem->getCount() == 1)
+ ilist->deleteItem(item_i);
+ else
+ mitem->remove(1);
+ }
+
+ /*
+ Add node.
+
+ This takes some time so it is done after the quick stuff
+ */
+ core::map<v3s16, MapBlock*> modified_blocks;
+ {
+ MapEditEventIgnorer ign(&m_ignore_map_edit_events);
+
+ std::string p_name = std::string(player->getName());
+ m_env->getMap().addNodeAndUpdate(p_above, n, modified_blocks, p_name);
+ }
+ /*
+ Set blocks not sent to far players
+ */
+ for(core::list<u16>::Iterator
+ i = far_players.begin();
+ i != far_players.end(); i++)
+ {
+ u16 peer_id = *i;
+ RemoteClient *client = getClient(peer_id);
+ if(client==NULL)
+ continue;
+ client->SetBlocksNotSent(modified_blocks);
+ }
+
+ /*
+ Run script hook
+ */
+ scriptapi_environment_on_placenode(m_lua, p_above, n, srp);
+
+ /*
+ Calculate special events
+ */
+
+ /*if(n.d == LEGN(m_nodedef, "CONTENT_MESE"))
+ {
+ u32 count = 0;
+ for(s16 z=-1; z<=1; z++)
+ for(s16 y=-1; y<=1; y++)
+ for(s16 x=-1; x<=1; x++)
+ {
+
+ }
+ }*/
+ }
+ /*
+ Place other item (not a block)
+ */
+ else
+ {
+ if(!build_priv)
+ {
+ infostream<<"Not allowing player to place item: "
+ "no build privileges"<<std::endl;
+ return;
+ }
+
+ // Calculate a position for it
+ v3f pos = player_pos;
+ if(pointed.type == POINTEDTHING_NOTHING)
+ {
+ infostream<<"Not allowing player to place item: "
+ "pointing to nothing"<<std::endl;
+ return;
+ }
+ else if(pointed.type == POINTEDTHING_NODE)
+ {
+ pos = intToFloat(p_above, BS);
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ pos = pointed_object->getBasePosition();
+
+ // Randomize a bit
+ pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
+ pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
+ }
+
+ //pos.Y -= BS*0.45;
+ //pos.Y -= BS*0.25; // let it drop a bit
+
+ /*
+ Check that the block is loaded so that the item
+ can properly be added to the static list too
+ */
+ v3s16 blockpos = getNodeBlockPos(floatToInt(pos, BS));
+ MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
+ if(block==NULL)
+ {
+ infostream<<"Error while placing item: "
+ "block not found"<<std::endl;
+ return;
+ }
+
+ actionstream<<player->getName()<<" places "<<item->getName()
+ <<" at "<<PP(pos)<<std::endl;
+
+ /*
+ Place the item
+ */
+ bool remove = item->dropOrPlace(m_env, srp, pos, true, -1);
+ if(remove && g_settings->getBool("creative_mode") == false)
+ {
+ InventoryList *ilist = player->inventory.getList("main");
+ if(ilist)
+ // Remove from inventory and send inventory
+ ilist->deleteItem(item_i);
+ }
+ }
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ // Right click object
+
+ if(!build_priv)
+ return;
+
+ // Skip if object has been removed
+ if(pointed_object->m_removed)
+ return;
+
+ actionstream<<player->getName()<<" right-clicks object "
+ <<pointed.object_id<<std::endl;
+
+ // Do stuff
+ pointed_object->rightClick(srp);
+ }
+
+ } // action == 3
+
+ /*
+ 4: use
+ */
+ else if(action == 4)
+ {
+ InventoryList *ilist = player->inventory.getList("main");
+ if(ilist == NULL)
+ return;
+
+ // Get item
+ InventoryItem *item = ilist->getItem(item_i);
+
+ // If there is no item, it is not possible to add it anywhere
+ if(item == NULL)
+ return;
+
+ // Requires build privs
+ if(!build_priv)
+ {
+ infostream<<"Not allowing player to use item: "
+ "no build privileges"<<std::endl;
+ return;
+ }
+
+ actionstream<<player->getName()<<" uses "<<item->getName()
+ <<", pointing at "<<pointed.dump()<<std::endl;
+
+ bool remove = item->use(m_env, srp, pointed);
+ if(remove && g_settings->getBool("creative_mode") == false)
+ {
+ InventoryList *ilist = player->inventory.getList("main");
+ if(ilist)
+ // Remove from inventory and send inventory
+ ilist->deleteItem(item_i);
+ }
+
+ } // action == 4
+
+ /*
+ Catch invalid actions
+ */
+ else
+ {
+ infostream<<"WARNING: Server: Invalid action "
+ <<action<<std::endl;
+ }
+
+ // Complete add_to_inventory_later
+ srp->completeAddToInventoryLater(item_i);
+
+ // Send inventory
+ // FIXME: Shouldn't be done unless something changed.
+ UpdateCrafting(player->peer_id);
+ SendInventory(player->peer_id);
+ }
else
{
infostream<<"Server::ProcessData(): Ignoring "
@@ -3865,6 +3813,31 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id,
con.Send(peer_id, 0, data, true);
}
+void Server::SendCraftItemDef(con::Connection &con, u16 peer_id,
+ ICraftItemDefManager *craftitemdef)
+{
+ DSTACK(__FUNCTION_NAME);
+ std::ostringstream os(std::ios_base::binary);
+
+ /*
+ u16 command
+ u32 length of the next item
+ serialized CraftItemDefManager
+ */
+ writeU16(os, TOCLIENT_CRAFTITEMDEF);
+ std::ostringstream tmp_os(std::ios::binary);
+ craftitemdef->serialize(tmp_os);
+ os<<serializeLongString(tmp_os.str());
+
+ // Make data buffer
+ std::string s = os.str();
+ infostream<<"Server::SendCraftItemDef(): Sending craft item definitions: size="
+ <<s.size()<<std::endl;
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ con.Send(peer_id, 0, data, true);
+}
+
/*
Non-static send methods
*/
@@ -4481,7 +4454,7 @@ void Server::HandlePlayerHP(Player *player, s16 damage)
void Server::RespawnPlayer(Player *player)
{
player->hp = 20;
- ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
+ ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
if(!repositioned){
v3f pos = findSpawnPos(m_env->getServerMap());
@@ -4626,6 +4599,10 @@ ICraftDefManager* Server::getCraftDefManager()
{
return m_craftdef;
}
+ICraftItemDefManager* Server::getCraftItemDefManager()
+{
+ return m_craftitemdef;
+}
ITextureSource* Server::getTextureSource()
{
return NULL;
@@ -4647,6 +4624,10 @@ IWritableCraftDefManager* Server::getWritableCraftDefManager()
{
return m_craftdef;
}
+IWritableCraftItemDefManager* Server::getWritableCraftItemDefManager()
+{
+ return m_craftitemdef;
+}
v3f findSpawnPos(ServerMap &map)
{
@@ -4776,7 +4757,7 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id
m_env->addPlayer(player);
/* Run scripts */
- ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
+ ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
scriptapi_on_newplayer(m_lua, srp);
/* Add stuff to inventory */