aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt8
-rw-r--r--src/client.cpp5
-rw-r--r--src/content_craft.cpp32
-rw-r--r--src/content_inventory.cpp12
-rw-r--r--src/content_mapblock.cpp60
-rw-r--r--src/content_mapnode.cpp26
-rw-r--r--src/content_mapnode.h3
-rw-r--r--src/content_nodemeta.cpp64
-rw-r--r--src/content_nodemeta.h23
-rw-r--r--src/defaultsettings.cpp1
-rw-r--r--src/environment.cpp7
-rw-r--r--src/map.cpp6
-rw-r--r--src/map.h2
-rw-r--r--src/mapgen.cpp26
-rw-r--r--src/nodemetadata.h3
-rw-r--r--src/server.cpp80
16 files changed, 330 insertions, 28 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 80ee0fc64..a753b6d87 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -74,7 +74,7 @@ else()
endif(APPLE)
endif(BUILD_CLIENT)
find_package(ZLIB REQUIRED)
- set(PLATFORM_LIBS -lpthread)
+ set(PLATFORM_LIBS -lpthread ${CMAKE_DL_LIBS})
#set(CLIENT_PLATFORM_LIBS -lXxf86vm)
# This way Xxf86vm is found on OpenBSD too
find_library(XXF86VM_LIBRARY Xxf86vm)
@@ -189,10 +189,10 @@ if(BUILD_CLIENT)
${PNG_LIBRARIES}
${X11_LIBRARIES}
${GETTEXT_LIBRARY}
- ${PLATFORM_LIBS}
- ${CLIENT_PLATFORM_LIBS}
${JTHREAD_LIBRARY}
${SQLITE3_LIBRARY}
+ ${PLATFORM_LIBS}
+ ${CLIENT_PLATFORM_LIBS}
)
endif(BUILD_CLIENT)
@@ -201,9 +201,9 @@ if(BUILD_SERVER)
target_link_libraries(
${PROJECT_NAME}server
${ZLIB_LIBRARIES}
- ${PLATFORM_LIBS}
${JTHREAD_LIBRARY}
${SQLITE3_LIBRARY}
+ ${PLATFORM_LIBS}
)
endif(BUILD_SERVER)
diff --git a/src/client.cpp b/src/client.cpp
index 81dedd144..fa600719e 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -429,7 +429,7 @@ void Client::step(float dtime)
snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
// This should be incremented in each version
- writeU16(&data[51], 1);
+ writeU16(&data[51], 2);
// Send as unreliable
Send(0, data, false);
@@ -1961,7 +1961,8 @@ void Client::addNode(v3s16 p, MapNode n)
try
{
//TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
- m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
+ std::string st = std::string("");
+ m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
}
catch(InvalidPositionException &e)
{}
diff --git a/src/content_craft.cpp b/src/content_craft.cpp
index 20ab5f069..866c1e532 100644
--- a/src/content_craft.cpp
+++ b/src/content_craft.cpp
@@ -297,6 +297,24 @@ InventoryItem *craft_get_result(InventoryItem **items)
}
}
+ // Locking Chest
+ {
+ ItemSpec specs[9];
+ specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+ specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ if(checkItemCombination(items, specs))
+ {
+ return new MaterialItem(CONTENT_LOCKABLE_CHEST, 1);
+ }
+ }
+
// Furnace
{
ItemSpec specs[9];
@@ -428,6 +446,20 @@ InventoryItem *craft_get_result(InventoryItem **items)
return new MaterialItem(CONTENT_LADDER, 1);
}
}
+
+ // Iron Apple
+ {
+ ItemSpec specs[9];
+ specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+ specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+ specs[4] = ItemSpec(ITEM_CRAFT, "apple");
+ specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+ specs[7] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+ if(checkItemCombination(items, specs))
+ {
+ return new CraftItem("apple_iron", 1);
+ }
+ }
return NULL;
}
diff --git a/src/content_inventory.cpp b/src/content_inventory.cpp
index de8f8e397..59997ee4b 100644
--- a/src/content_inventory.cpp
+++ b/src/content_inventory.cpp
@@ -71,6 +71,10 @@ std::string item_craft_get_image_name(const std::string &subname)
return "scorched_stuff.png";
else if(subname == "firefly")
return "firefly.png";
+ else if(subname == "apple")
+ return "apple.png";
+ else if(subname == "apple_iron")
+ return "apple_iron.png";
else
return "cloud.png"; // just something
}
@@ -126,6 +130,10 @@ bool item_craft_is_eatable(const std::string &subname)
{
if(subname == "cooked_rat")
return true;
+ else if(subname == "apple")
+ return true;
+ else if(subname == "apple_iron")
+ return true;
return false;
}
@@ -133,6 +141,10 @@ s16 item_craft_eat_hp_change(const std::string &subname)
{
if(subname == "cooked_rat")
return 6; // 3 hearts
+ else if(subname == "apple")
+ return 4; // 2 hearts
+ else if(subname == "apple_iron")
+ return 8; // 4 hearts
return 0;
}
diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp
index 482b9eb63..1cc37b969 100644
--- a/src/content_mapblock.cpp
+++ b/src/content_mapblock.cpp
@@ -188,6 +188,16 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
AtlasPointer pa_papyrus = g_texturesource->getTexture(
g_texturesource->getTextureId("papyrus.png"));
material_papyrus.setTexture(0, pa_papyrus.atlas);
+
+ // Apple material
+ video::SMaterial material_apple;
+ material_apple.setFlag(video::EMF_LIGHTING, false);
+ material_apple.setFlag(video::EMF_BILINEAR_FILTER, false);
+ material_apple.setFlag(video::EMF_FOG_ENABLE, true);
+ material_apple.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+ AtlasPointer pa_apple = g_texturesource->getTexture(
+ g_texturesource->getTextureId("apple.png"));
+ material_apple.setTexture(0, pa_apple.atlas);
// junglegrass material
video::SMaterial material_junglegrass;
@@ -1203,6 +1213,56 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// Add to mesh collector
collector.append(material_ladder, vertices, 4, indices, 6);
}
+ else if(n.getContent() == CONTENT_APPLE)
+ {
+ u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
+ video::SColor c = MapBlock_LightColor(255, l);
+
+ for(u32 j=0; j<4; j++)
+ {
+ video::S3DVertex vertices[4] =
+ {
+ video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
+ pa_apple.x0(), pa_apple.y1()),
+ video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
+ pa_apple.x1(), pa_apple.y1()),
+ video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
+ pa_apple.x1(), pa_apple.y0()),
+ video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
+ pa_apple.x0(), pa_apple.y0()),
+ };
+
+ if(j == 0)
+ {
+ for(u16 i=0; i<4; i++)
+ vertices[i].Pos.rotateXZBy(45);
+ }
+ else if(j == 1)
+ {
+ for(u16 i=0; i<4; i++)
+ vertices[i].Pos.rotateXZBy(-45);
+ }
+ else if(j == 2)
+ {
+ for(u16 i=0; i<4; i++)
+ vertices[i].Pos.rotateXZBy(135);
+ }
+ else if(j == 3)
+ {
+ for(u16 i=0; i<4; i++)
+ vertices[i].Pos.rotateXZBy(-135);
+ }
+
+ for(u16 i=0; i<4; i++)
+ {
+ vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
+ }
+
+ u16 indices[] = {0,1,2,2,3,0};
+ // Add to mesh collector
+ collector.append(material_apple, vertices, 4, indices, 6);
+ }
+ }
}
}
#endif
diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp
index 70f465130..a573ca141 100644
--- a/src/content_mapnode.cpp
+++ b/src/content_mapnode.cpp
@@ -581,6 +581,20 @@ void content_mapnode_init()
f->initial_metadata = new ChestNodeMetadata();
setWoodLikeDiggingProperties(f->digging_properties, 1.0);
+ i = CONTENT_LOCKABLE_CHEST;
+ f = &content_features(i);
+ f->param_type = CPT_FACEDIR_SIMPLE;
+ f->setAllTextures("chest_side.png");
+ f->setTexture(0, "chest_top.png");
+ f->setTexture(1, "chest_top.png");
+ f->setTexture(5, "chest_lock.png"); // Z-
+ f->setInventoryTexture("chest_lock.png");
+ //f->setInventoryTextureCube("chest_top.png", "chest_side.png", "chest_side.png");
+ f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
+ if(f->initial_metadata == NULL)
+ f->initial_metadata = new LockingChestNodeMetadata();
+ setWoodLikeDiggingProperties(f->digging_properties, 1.0);
+
i = CONTENT_FURNACE;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
@@ -638,6 +652,18 @@ void content_mapnode_init()
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 3.0);
+ i = CONTENT_APPLE;
+ f = &content_features(i);
+ f->setInventoryTexture("apple.png");
+ f->param_type = CPT_LIGHT;
+ f->light_propagates = true;
+ f->sunlight_propagates = true;
+ f->solidness = 0; // drawn separately, makes no faces
+ f->walkable = false;
+ f->air_equivalent = true;
+ f->dug_item = std::string("CraftItem apple 1");
+ f->digging_properties.set("", DiggingProperties(true, 0.0, 0));
+
// NOTE: Remember to add frequently used stuff to the texture atlas in tile.cpp
diff --git a/src/content_mapnode.h b/src/content_mapnode.h
index 1f6292ba4..366c9b1a0 100644
--- a/src/content_mapnode.h
+++ b/src/content_mapnode.h
@@ -48,6 +48,7 @@ MapNode mapnode_translate_to_internal(MapNode n_from, u8 version);
#define CONTENT_SIGN_WALL 14
#define CONTENT_CHEST 15
#define CONTENT_FURNACE 16
+#define CONTENT_LOCKABLE_CHEST 17
#define CONTENT_FENCE 21
@@ -83,6 +84,8 @@ MapNode mapnode_translate_to_internal(MapNode n_from, u8 version);
#define CONTENT_JUNGLEGRASS 0x816
#define CONTENT_NC 0x817
#define CONTENT_NC_RB 0x818
+#define CONTENT_APPLE 0x819
+
#endif
diff --git a/src/content_nodemeta.cpp b/src/content_nodemeta.cpp
index 1552c8e15..e79ff6d54 100644
--- a/src/content_nodemeta.cpp
+++ b/src/content_nodemeta.cpp
@@ -118,6 +118,70 @@ std::string ChestNodeMetadata::getInventoryDrawSpecString()
}
/*
+ LockingChestNodeMetadata
+*/
+
+// Prototype
+LockingChestNodeMetadata proto_LockingChestNodeMetadata;
+
+LockingChestNodeMetadata::LockingChestNodeMetadata()
+{
+ NodeMetadata::registerType(typeId(), create);
+
+ m_inventory = new Inventory();
+ m_inventory->addList("0", 8*4);
+}
+LockingChestNodeMetadata::~LockingChestNodeMetadata()
+{
+ delete m_inventory;
+}
+u16 LockingChestNodeMetadata::typeId() const
+{
+ return CONTENT_LOCKABLE_CHEST;
+}
+NodeMetadata* LockingChestNodeMetadata::create(std::istream &is)
+{
+ LockingChestNodeMetadata *d = new LockingChestNodeMetadata();
+ d->setOwner(deSerializeString(is));
+ d->m_inventory->deSerialize(is);
+ return d;
+}
+NodeMetadata* LockingChestNodeMetadata::clone()
+{
+ LockingChestNodeMetadata *d = new LockingChestNodeMetadata();
+ *d->m_inventory = *m_inventory;
+ return d;
+}
+void LockingChestNodeMetadata::serializeBody(std::ostream &os)
+{
+ os<<serializeString(m_text);
+ m_inventory->serialize(os);
+}
+std::string LockingChestNodeMetadata::infoText()
+{
+ return "Locking Chest";
+}
+bool LockingChestNodeMetadata::nodeRemovalDisabled()
+{
+ /*
+ Disable removal if chest contains something
+ */
+ InventoryList *list = m_inventory->getList("0");
+ if(list == NULL)
+ return false;
+ if(list->getUsedSlots() == 0)
+ return false;
+ return true;
+}
+std::string LockingChestNodeMetadata::getInventoryDrawSpecString()
+{
+ return
+ "invsize[8,9;]"
+ "list[current_name;0;0,0;8,4;]"
+ "list[current_player;main;0,5;8,4;]";
+}
+
+/*
FurnaceNodeMetadata
*/
diff --git a/src/content_nodemeta.h b/src/content_nodemeta.h
index 50decd910..e20334312 100644
--- a/src/content_nodemeta.h
+++ b/src/content_nodemeta.h
@@ -62,6 +62,29 @@ private:
Inventory *m_inventory;
};
+class LockingChestNodeMetadata : public NodeMetadata
+{
+public:
+ LockingChestNodeMetadata();
+ ~LockingChestNodeMetadata();
+
+ virtual u16 typeId() const;
+ static NodeMetadata* create(std::istream &is);
+ virtual NodeMetadata* clone();
+ virtual void serializeBody(std::ostream &os);
+ virtual std::string infoText();
+ virtual Inventory* getInventory() {return m_inventory;}
+ virtual bool nodeRemovalDisabled();
+ virtual std::string getInventoryDrawSpecString();
+
+ virtual std::string getOwner(){ return m_text; }
+ virtual void setOwner(std::string t){ m_text = t; }
+
+private:
+ Inventory *m_inventory;
+ std::string m_text;
+};
+
class FurnaceNodeMetadata : public NodeMetadata
{
public:
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 163ed0884..dec7f17bd 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -79,6 +79,7 @@ void set_default_settings()
// Server stuff
g_settings.setDefault("motd", "");
+ g_settings.setDefault("max_users", "20");
g_settings.setDefault("enable_experimental", "false");
g_settings.setDefault("creative_mode", "false");
g_settings.setDefault("enable_damage", "true");
diff --git a/src/environment.cpp b/src/environment.cpp
index ea33274df..ff570554d 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -1345,8 +1345,6 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
i.atEnd()==false; i++)
{
ServerActiveObject* obj = i.getNode()->getValue();
- u16 id = i.getNode()->getKey();
- v3f objectpos = obj->getBasePosition();
// This shouldn't happen but check it
if(obj == NULL)
@@ -1357,9 +1355,12 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
continue;
}
+ u16 id = i.getNode()->getKey();
+ v3f objectpos = obj->getBasePosition();
+
// The block in which the object resides in
v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
-
+
// If block is active, don't remove
if(m_active_blocks.contains(blockpos_o))
continue;
diff --git a/src/map.cpp b/src/map.cpp
index ecd12bddb..eb55d3a57 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -890,7 +890,7 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
/*
*/
void Map::addNodeAndUpdate(v3s16 p, MapNode n,
- core::map<v3s16, MapBlock*> &modified_blocks)
+ core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name)
{
/*PrintInfo(m_dout);
m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
@@ -1014,6 +1014,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
if(meta_proto)
{
NodeMetadata *meta = meta_proto->clone();
+ meta->setOwner(player_name);
setNodeMetadata(p, meta);
}
@@ -1290,7 +1291,8 @@ bool Map::addNodeWithEvent(v3s16 p, MapNode n)
bool succeeded = true;
try{
core::map<v3s16, MapBlock*> modified_blocks;
- addNodeAndUpdate(p, n, modified_blocks);
+ std::string st = std::string("");
+ addNodeAndUpdate(p, n, modified_blocks, st);
// Copy modified_blocks to event
for(core::map<v3s16, MapBlock*>::Iterator
diff --git a/src/map.h b/src/map.h
index cb649addd..b58ba047b 100644
--- a/src/map.h
+++ b/src/map.h
@@ -205,7 +205,7 @@ public:
These handle lighting but not faces.
*/
void addNodeAndUpdate(v3s16 p, MapNode n,
- core::map<v3s16, MapBlock*> &modified_blocks);
+ core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name);
void removeNodeAndUpdate(v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks);
diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index 0018b9919..a07f4cac8 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -80,11 +80,12 @@ static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
}
#endif
-static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
+static void make_tree(VoxelManipulator &vmanip, v3s16 p0, bool is_apple_tree)
{
MapNode treenode(CONTENT_TREE);
MapNode leavesnode(CONTENT_LEAVES);
-
+ MapNode applenode(CONTENT_APPLE);
+
s16 trunk_h = myrand_range(4, 5);
v3s16 p1 = p0;
for(s16 ii=0; ii<trunk_h; ii++)
@@ -147,8 +148,14 @@ static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
&& vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
continue;
u32 i = leaves_a.index(x,y,z);
- if(leaves_d[i] == 1)
- vmanip.m_data[vi] = leavesnode;
+ if(leaves_d[i] == 1) {
+ bool is_apple = myrand_range(0,99) < 10;
+ if(is_apple_tree && is_apple) {
+ vmanip.m_data[vi] = applenode;
+ } else {
+ vmanip.m_data[vi] = leavesnode;
+ }
+ }
}
}
@@ -2129,7 +2136,16 @@ void make_block(BlockMakeData *data)
p.Y++;
//if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
if(is_jungle == false)
- make_tree(vmanip, p);
+ {
+ bool is_apple_tree;
+ if(myrand_range(0,4) != 0)
+ is_apple_tree = false;
+ else
+ is_apple_tree = noise2d_perlin(
+ 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
+ data->seed+342902, 3, 0.45) > 0.2;
+ make_tree(vmanip, p, is_apple_tree);
+ }
else
make_jungletree(vmanip, p);
}
diff --git a/src/nodemetadata.h b/src/nodemetadata.h
index de682f9b6..d81ade96c 100644
--- a/src/nodemetadata.h
+++ b/src/nodemetadata.h
@@ -65,6 +65,9 @@ public:
// Used to make custom inventory menus.
// See format in guiInventoryMenu.cpp.
virtual std::string getInventoryDrawSpecString(){return "";}
+ // primarily used for locking chests, but others can play too
+ virtual std::string getOwner(){ return std::string(""); }
+ virtual void setOwner(std::string t){ }
protected:
static void registerType(u16 id, Factory f);
diff --git a/src/server.cpp b/src/server.cpp
index 46993913f..5395d7618 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -2013,6 +2013,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
L"Your client is too old. Please upgrade.");
return;
}
+
+ /* Uhh... this should actually be a warning but let's do it like this */
+ if(net_proto_version < 2)
+ {
+ SendAccessDenied(m_con, peer_id,
+ L"Your client is too old. Please upgrade.");
+ return;
+ }
/*
Set up player
@@ -2091,11 +2099,21 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
stringToPrivs(g_settings.get("default_privs")));
m_authmanager.save();
}
+
+ // Enforce user limit.
+ // Don't enforce for users that have some admin right
+ if(m_clients.size() >= g_settings.getU16("max_users") &&
+ (m_authmanager.getPrivs(playername)
+ & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 &&
+ playername != g_settings.get("name"))
+ {
+ SendAccessDenied(m_con, peer_id, L"Too many users.");
+ return;
+ }
// Get player
Player *player = emergePlayer(playername, password, peer_id);
-
/*{
// DEBUG: Test serialization
std::ostringstream test_os;
@@ -2876,7 +2894,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
MapEditEventIgnorer ign(&m_ignore_map_edit_events);
- m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
+ 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
@@ -3203,7 +3222,46 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
// Disallow moving items if not allowed to build
else if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
+ {
return;
+ }
+ // if it's a locking chest, only allow the owner or server admins to move items
+ else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
+ {
+ Strfnd fn(ma->from_inv);
+ 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(","));
+ NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
+ if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
+ LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
+ if (lcm->getOwner() != player->getName())
+ return;
+ }
+ }
+ }
+ else if (ma->to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
+ {
+ Strfnd fn(ma->to_inv);
+ 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(","));
+ NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
+ if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
+ LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
+ if (lcm->getOwner() != player->getName())
+ return;
+ }
+ }
+ }
}
if(disable_action == false)
@@ -4104,7 +4162,7 @@ void Server::UpdateCrafting(u16 peer_id)
InventoryList *clist = player->inventory.getList("craft");
InventoryList *rlist = player->inventory.getList("craftresult");
- if(rlist->getUsedSlots() == 0)
+ if(rlist && rlist->getUsedSlots() == 0)
player->craftresult_is_preview = true;
if(rlist && player->craftresult_is_preview)
@@ -4381,16 +4439,16 @@ void Server::handlePeerChange(PeerChange &c)
// Collect information about leaving in chat
std::wstring message;
{
- std::wstring name = L"unknown";
Player *player = m_env.getPlayer(c.peer_id);
if(player != NULL)
- name = narrow_to_wide(player->getName());
-
- message += L"*** ";
- message += name;
- message += L" left game";
- if(c.timeout)
- message += L" (timed out)";
+ {
+ std::wstring name = narrow_to_wide(player->getName());
+ message += L"*** ";
+ message += name;
+ message += L" left game";
+ if(c.timeout)
+ message += L" (timed out)";
+ }
}
/*// Delete player