diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 8 | ||||
-rw-r--r-- | src/client.cpp | 5 | ||||
-rw-r--r-- | src/content_craft.cpp | 32 | ||||
-rw-r--r-- | src/content_inventory.cpp | 12 | ||||
-rw-r--r-- | src/content_mapblock.cpp | 60 | ||||
-rw-r--r-- | src/content_mapnode.cpp | 26 | ||||
-rw-r--r-- | src/content_mapnode.h | 3 | ||||
-rw-r--r-- | src/content_nodemeta.cpp | 64 | ||||
-rw-r--r-- | src/content_nodemeta.h | 23 | ||||
-rw-r--r-- | src/defaultsettings.cpp | 1 | ||||
-rw-r--r-- | src/environment.cpp | 7 | ||||
-rw-r--r-- | src/map.cpp | 6 | ||||
-rw-r--r-- | src/map.h | 2 | ||||
-rw-r--r-- | src/mapgen.cpp | 26 | ||||
-rw-r--r-- | src/nodemetadata.h | 3 | ||||
-rw-r--r-- | src/server.cpp | 80 |
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 @@ -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 |